Число треугольник флип


30

Скажем, вы перечислите положительные целые числа в треугольнике, а затем переверните его слева направо. Получив номер, выведите номер, на который он отправлен. Это самообратное отображение.

         1                      1         
       2   3                  3   2       
     4   5   6    <--->     6   5   4     
   7   8   9  10         10   9   8   7   
11  12  13  14  15     15  14  13  12  11

Это n-й элемент A038722 с одним индексом:

1, 3, 2, 6, 5, 4, 10, 9, 8, 7, 15, 14, 13, 12, 11, ...

Эта последовательность инвертирует непрерывные куски натуральных чисел с увеличением длины:

 1, 3, 2, 6, 5, 4, 10, 9, 8, 7, 15, 14, 13, 12, 11, ...
<-><----><-------><-----------><------------------>

Тестовые случаи:

1 -> 1
2 -> 3
3 -> 2
4 -> 6
14 -> 12
990 -> 947
991 -> 1035
1000 -> 1026
1035 -> 991
1036 -> 1081
12345 -> 12305

Leaderboard:

Ответы:


15

JavaScript (ES7), 26 байт

n=>((2*n)**.5+.5|0)**2-n+1

Реализация следующей формулы от OEIS :

формула

демонстрация


Мне нравится операция ИЛИ, чтобы разделить ее на целое число! хорошая работа!
CraigR8806

7

Желе , 8 7 байт

RṁR€UFi

Спасибо @ErikTheOutgolfer за сохранение 1 байта!

Попробуйте онлайн!

Как это работает

RṁR€UFi  Main link. Argument: n

R        Range; yield [1, ..., n].
  R€     Range each; yield [[1], [1, 2], [1, 2, 3], ..., [1, ..., n]].
 ṁ       Mold the left argument like the right one, yielding
         [[1], [2, 3], [4, 5, 6], ...]. The elements of the left argument are 
         repeated cyclically to fill all n(n+1)/2 positions in the right argument.
    U    Upend; reverse each flat array, yielding [[1], [3, 2], [6, 5, 4], ...].
     F   Flatten, yielding [1, 3, 2, 6, 5, 4, ...].
      i  Index; find the first index of n in the result.

6

Алиса , 27 байт

Спасибо Sp3000 за .Cидею.

/o
\i@/.2:e2,tE*Y~Z.H2*~.C+

Попробуйте онлайн!

объяснение

Я думаю, что может быть более короткий способ вычислить это, используя треугольные числа, но я подумал, что это интересное злоупотребление встроенным, так что вот другое решение.

Основная идея состоит в том, чтобы использовать встроенные модули «pack» и «unpack» Алисы. «Пакет», или Z, принимает два целых числа, отображает их биективно в одно целое число. «Распаковать», илиY , инвертирует эту биекцию и превращает одно целое в два. Обычно это можно использовать для хранения списка или дерева целых чисел в одном (большом) целом числе и восстановления отдельных значений позже. Однако в этом случае мы можем использовать функции в обратном порядке, чтобы позволить природе биекции работать на нас.

Распаковка одного целого числа в два целых состоит в основном из трех шагов:

  1. Карта ℤ → ℕ (включая ноль) с простым «складыванием». То есть отображать отрицательные целые числа в нечетные натуральные числа, а неотрицательные целые числа - в четные натуральные.
  2. Карта ℕ → ℕ 2 , используя функцию сопряжения Кантора . То есть натуральные числа записываются по диагонали бесконечной сетки, и мы возвращаем индексы:

       ...
    3  9 ...
    2  5 8 ...
    1  2 4 7 ...
    0  0 1 3 6 ...
    
       0 1 2 3
    

    Например 8, будет сопоставлен с парой (1, 2).

  3. Карта 2 → ℤ 2 , используя обратный шаг 1 на каждое целое по отдельности. То есть нечетные натуральные числа отображаются в отрицательные целые числа, а четные натуральные числа отображаются в неотрицательные целые числа.

Чтобы упаковать два целых числа в одно, мы просто инвертируем каждый из этих шагов.

Теперь мы можем видеть, что структура функции сопряжения Кантора удобно кодирует нужный нам треугольник (хотя значения не совпадают). Чтобы перевернуть эти диагонали, все, что нам нужно сделать, это поменять местами x и y координаты на сетке.

К сожалению, поскольку все три из вышеперечисленных шагов объединены в одну встроенную Y(или Z), нам нужно отменить отображения ℤ → ℕ или ℕ → ourselves самостоятельно. Тем не менее, при этом мы можем сохранить пару байтов, непосредственно используя сопоставления ℕ + → ℤ или ℤ → ℕ + , чтобы позаботиться об ошибке «один за другим» в таблице. Итак, вот весь алгоритм:

  1. Карта + → ℤ с использованием (n / 2) * (-1) n-1 . Это отображение выбрано таким, что оно отменяет неявное отображение ℤ → during во время распаковки, за исключением того, что оно сдвигает значение вниз на 1.
  2. Распакуйте результат в два целых числа.
  3. Поменяйте их местами.
  4. Снова упакуйте измененные значения в одно целое число.
  5. Карта ℤ → ℕ + с использованием | 2n | + (n≥0) . Опять же, это отображение выбрано таким, что оно отменяет неявное отображение ℕ → during во время упаковки, за исключением того, что оно сдвигает значение на 1.

С этим из пути мы можем смотреть на программу:

/o
\i@/...

Это просто структура для линейных арифметических программ с целочисленным вводом и выводом.

.    Duplicate the input.
2:   Halve it.
e    Push -1.
2,   Pull up the other copy of the input.
t    Decrement.
E    Raise -1 to this power.
*    Multiply. We've now computed (n/2) * (-1)^(n-1).
Y    Unpack.
~    Swap.
Z    Pack.
.H   Duplicate the result and take its absolute value.
2*   Double.
~    Swap with other copy.
.C   Compute k-choose-k. That's 1 for k ≥ 0 and 0 for k < 0.
+    Add. We've now computed |2n| + (n≥0).



4

Октава , 71 68 байт

3 байта сохранены благодаря Конору О'Брайену .

x=triu(ones(n=input('')));x(~~x)=1:nnz(x);disp(nonzeros(flip(x))(n))

Это не работает для больших входов из-за ограничений памяти.

Попробуйте онлайн!

объяснение

Рассмотрим ввод n = 4. Код сначала строит матрицу

 1     1     1     1
 0     1     1     1
 0     0     1     1
 0     0     0     1

Затем он заменяет ненулевые элементы в столбцах порядка (вниз, а затем по горизонтали) от 1, 2, 3...:

 1     2     4     7
 0     3     5     8
 0     0     6     9
 0     0     0    10

Затем он переворачивает матрицу по вертикали:

 0     0     0    10
 0     0     6     9
 0     3     5     8
 1     2     4     7

Наконец, он принимает n-ное ненулевое значение в мажорном столбце, который в данном случае равен 6.


1
@ rahnema1 Это eгений! Вы обязательно должны опубликовать его как ответ, вместе с другими вашими очень хорошими предложениями. Что касается ans =, я никогда не уверен, что это действительно или нет
Луис Мендо

4

Haskell , 31 байт

r=round
f n=r(sqrt$2*n)^2-r n+1

Попробуйте онлайн!

Этот ответ просто использует формулу. Это наименее интересный ответ здесь, но он также оказывается самым гольфом.

Haskell , 38 36 34 байта

x!y|x<=y=1-x|v<-y+1=v+(x-y)!v
(!0)

Попробуйте онлайн!

(!0) это функция без точек, с которой мы имеем дело.

объяснение

Позвольте мне начать с того, что я очень доволен этим ответом.

Основная идея здесь заключается в том, что, если мы удалим наибольшее треугольное число, меньшее нашего ввода, мы можем обратить его вспять и добавить обратно треугольное число. Таким образом, мы определяем оператор !, который !принимает наш обычный ввод x, но он также требует дополнительного числа y. yотслеживает размер растущего треугольного числа. Если x>yмы хотим рекурсию, мы уменьшаем xпутем yи увеличения yна единицу. Итак, мы рассчитаем (x-y)!(y+1)и добавим y+1к нему. Если x<=yмы достигли нашего базового случая, для обратного xразмещения в строке треугольника мы возвращаемся1-x .

Haskell , 54 байта

f x|u<-div(x^2-x)2=[u+x,u+x-1..u+1]
(!!)$0:(>>=)[1..]f

Попробуйте онлайн!

(!!)$0:(>>=)[1..]f это бессмысленная функция

объяснение

Первое, что нас интересует f, f- это функция, которая принимает xи возвращает xстроку в обратном порядке. Это делается путем вычисления первого x-1треугольного числа и присвоения его u. u<-div(x^2-x)2, Затем мы возвращаем список [u+x,u+x-1..u+1]. u+xэто xтреугольное число и первое число в строке, u+x-1на единицу меньше, чем второе число в строкеu+1 на единицу больше, чем последнее треугольное число и, следовательно, последнее число в строке.

После того, как fу нас есть, мы формируем список (>>=)[1..]f, который является уплощением треугольника. Мы добавляем ноль в начало, 0:чтобы наши ответы не были смещены на единицу, и добавляем его в нашу функцию индексации(!!) .

Haskell , 56 байт

f 0=[0]
f x|u<-f(x-1)!!0=[u+x,u+x-1..u+1]
(!!)$[0..]>>=f

Попробуйте онлайн!

Это на 2 байта длиннее, но, на мой взгляд, немного более элегантно.


3

C (gcc) , 48 байтов

k,j,l;f(n){for(k=j=0;k<n;)l=k,k+=++j;n=1+k-n+l;}

Попробуйте онлайн!

Возможно, неоптимальный, но я очень доволен этим. Использует тот факт, что

NTF N = T N + A057944 ( N ) - N + 1

(Если я правильно написал формулу, то есть.)


Вы не вызываете return, но используется возвращаемое значение. Это неопределенное поведение.
2501

@ 2501 Пока программа работает, она разрешена. И запись в первый аргумент функции эквивалентна возвращению значения.
Конор О'Брайен,

И запись в первый аргумент функции эквивалентна возвращению значения. Такого в языке Си не существует. Стандарт даже явно говорит, что использование возвращаемого значения из функции, которая не возвращает, является неопределенным поведением.
2501

1
@ 2501 Похоже, вы путаете среду C (gcc) со спецификацией C. Да, язык C / spec называет его неопределенным, но он реализован как таковой. Поэтому, когда я говорю «эквивалент», я определенно имею в виду реализацию C gcc и большинством других компиляторов. На PPCG мы не пишем «идеальный» код - большая часть кода идет вразрез со спецификацией ради игры в гольф. Как я уже сказал, пока это работает, это правильный ответ.
Конор О'Брайен,

@ 2501 Я рекомендую вам прочитать некоторые статьи на мета-сайте, особенно эту .
Конор О'Брайен,

2

05AB1E , 30 байтов

U1V[YLO>X›iYLOX-UY<LO>X+,q}Y>V

Попробуйте онлайн!


Я собирался сказать: «Что? Ответ 05AB1E без Unicode?» но затем один не-ASCII-персонаж разрушает его ...: P Хороший первый ответ, тем не менее, добро пожаловать в программирование головоломок и Code Golf!
clismique

@ Qwerp-Derp Спасибо большое! Я только начал изучать этот язык, поэтому я не удивлен, что мой ответ был таким плохим.
Эдуардо Хофел

2

Шелуха , 6 байт

!ṁ↔´CN

Попробуйте онлайн!

объяснение

!ṁ↔´CN  -- implicit input N, for example: 4
   ´ N  -- duplicate the natural numbers:
           [1,2,3,…] [1,2,3,…]
    C   -- cut the second argument into sizes of the first:
           [[1],[2,3],[4,5,6],[7,8,9,10],…]
 ṁ↔     -- map reverse and flatten:
           [1,3,2,6,5,4,10,9,8,7,15,…
!       -- index into that list:
           6

2

тинилисп , 78 байт

(d _(q((R N T)(i(l T N)(_(a R 1)N(a T R))(a 2(a T(s T(a N R
(d f(q((N)(_ 2 N 1

Определяет функцию, fкоторая выполняет сопоставление.Попробуйте онлайн!

Ungolfed

Мы находим наименьшее треугольное число, которое больше или равно входному номеру, а также в какой строке треугольника находится наше число. Из них мы можем вычислить перевернутую версию числа.

  • Если текущее треугольное число меньше N, перейдите к следующей строке треугольника. (Мы рассматриваем верхний ряд как ряд 2, чтобы сделать математику проще.)
  • В противном случае перевернутая версия N имеет вид (TN) + (TR) +2.

Основная функция flipпросто вызывает вспомогательную функцию, _flipначиная с верхнего ряда.

(load library)

(def _flip
 (lambda (Num Row Triangular)
  (if (less? Triangular Num)
   (_flip Num (inc Row) (+ Triangular Row))
   (+ 2
    (- Triangular Num)
    (- Triangular Row))))))

(def flip
 (lambda (Num) (_flip Num 2 1)))

1

05AB1E , 9 байтов

·LD£í˜¹<è

Попробуйте онлайн!

объяснение

·L          # push range [1 ... 2n]
  D         # duplicate
   £        # split the first list into pieces with size dependent on the second list
    í       # reverse each sublist
     ˜      # flatten
      ¹<è   # get the element at index <input>-1

К сожалению, выравнивание массивов не очень хорошо справляется с большими списками.
Ценой в 1 байт мы могли бы сделать · t2z + ïn¹->, используя математическую формулу, floor(sqrt(2*n)+1/2)^2 - n + 1найденную в OEIS .


1

Пакетная, 70 байт

@set/ai=%2+1,j=%3+i
@if %j% lss %1 %0 %1 %i% %j%
@cmd/cset/ai*i+1-%1

Использует цикл, чтобы найти индекс треугольного числа, по крайней мере, такого же размера, как n.




0

APL (Дьялог), 27 байт

У меня есть два решения на одном и том же bytecount.

Поезд:

⊢⊃⊃∘(,/{⌽(+/⍳⍵-1)+⍳⍵}¨∘⍳)

Попробуйте онлайн!

И DFN:

{⍵⊃⊃((⍳⍵),.{1+⍵-⍳⍺}+\⍳⍵)}

Попробуйте онлайн!

Оба эти решения сначала создают перевернутый треугольник, а затем извлекают элемент по индексу, указанному аргументом ( 1-based).


0

J, 25 байт

3 :'>:y-~*:>.-:<:%:>:8*y'

В качестве объяснения рассмотрим f(n) = n(n+1)/2. f(r), Учитывая строку r, возвращает крайний левый номер - rй строке зеркальном треугольника. Теперь рассмотрим g(n) = ceiling[f⁻¹(n)]. g(i)с учетом индекса iвозвращает строку, по которой найден индекс i. Затем f(g(n))возвращает крайний левый номер строки, в которой найден индекс n. Итак, h(n) = f(g(n)) - (n - f(g(n)-1)) + 1является ответом на вышеуказанную проблему.

Упрощая, мы получаем h(n) = [g(n)]² - n + 1 = ceiling[(-1 + sqrt(1 + 8n))/2]² - n + 1.

Из формул @ Арнаулда видно, что:

ceiling[(-1 + sqrt(1 + 8n))/2] = floor[1/2 + sqrt(2n)],


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.