B U I L DAN E S т


30

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

Правила

  • Ваш код должен создавать уникальный действительный вложенный массив для каждого целого числа 0 ‌≤ n ‌ <2 31 .
  • Каждый возможный вложенный массив с до 16 открытых скобок должен быть выведен в этом диапазоне. (Это не означает, что ваш код никогда не сможет вывести вложенный массив с более чем 16 открытыми скобками.)
  • Ваш код может выводить строковое представление вложенного массива вместо фактического массива (с запятыми или без них).

Одно из возможных сопоставлений:

0 -> []
1 -> [[]]
2 -> [[[]]]
3 -> [[], []]
4 -> [[[[]]]]
5 -> [[[], []]]
6 -> [[[]], []]
7 -> [[], [[]]]
8 -> [[], [], []]
9 -> [[[[[]]]]]
etc.

счет

Это , поэтому выигрывает самый короткий код в байтах.


Есть ли ограничения по времени / памяти?
Деннис

@ Денис 1 час кажется разумным для ограничения времени? Я понятия не имею, что разумно для памяти.
ETHproductions

Память не имеет большого значения, если есть ограничение по времени. Один час кажется очень щедрым. Я не хотел бы ждать целый час, чтобы проверить, достаточно ли быстрый мой код.
Деннис

4
Я бы предпочел никаких временных ограничений. Это дает больше возможностей для оригинальности
Тон Хоспел

2
@TonHospel Вы можете выводить без запятых. Я предполагаю, что никакие временные ограничения не будут нормальными, если вы можете доказать, что ваша запись действительна.
ETHпродукция

Ответы:


12

Python 2,7, 172 149 124 118 байт

x=input();y="";z=0
for b in bin(x)[2+(x<1):]:y+="[]"[b<"1"];z+=b>"0"or-1;z+=99*(z<0)
print"["+(y,"[]"*(x+16))[z>0]+"]"

Объяснение:

Определите биекцию с помощью [1и ]0. Любое расположение скобок может быть записано в виде двоичного числа и наоборот, например, [][]1010(10) и [[][]]110100(52). Все действительные схемы, содержащие до 15 открытых скобок (всего 30 скобок), охватываются числами до 30 разрядов (без учета начальных нулей), которые в точности равны числам, меньшим 2 31 .

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

Недопустимые размещения заменяются в операторе печати длинными последовательностями скобок, чтобы избежать коллизий. Например, 11(3) ↔ [[недопустимо, поэтому вместо этого мы объединяем 3 + 16 скобок. Это гарантирует, что все договоренности являются уникальными.

Результирующее расположение помещается в пару скобок, чтобы создать вложенный массив, так что 1010(10) становится [[][]]и 110100(52) становится [[[][]]]. Дополнительная открытая скобка означает, что теперь мы закрыли все массивы 16 открытыми скобками.


Следующая программа может быть использована для определения числа для данного массива до 16 скобок.

s=raw_input();o="";
for c in s[1:-1]:
 if c=="[":o+="1"
 if c=="]":o+="0"
print int(o,2)

Хорошее злоупотребление намерением оператора, когда он определил «уникальный»
Тон Хоспел

Это просто гений. Отлично сработано. (И допускается формат без запятой.)
ETHproductions

12

Python, 153 128 байт

s=l=0;r="";n=input()
for d in bin(n)[2:]*(n>0):c=d<"1";l=[l,s>1][c];r+="]"*c+(1-l*c)*"[";s+=1-c-l*c
print"["+r+"["*l+"]"*(s+l+1)

Мы отображаем число n во вложенный список, просматривая его двоичные цифры слева направо. Этот алгоритм работает для любого числа, а не только до 2 32 .

  1. Если текущая двоичная цифра - 1, выведите [.
  2. В противном случае, если последовательность выводимых нами скобок будет сбалансирована одной закрывающей скобкой, выведите ][.
  3. В противном случае, если это последний 0 в двоичном числе, выведите ][.
  4. В противном случае вывод ].

Наконец, мы закрываем все открытые скобки.


5

Ложка , 63 байта (501 бит)

000001001001001011001101001010011011111001010001000000101010
101101100110100101101001000101100010001000000100011000010000
000000000000001110111110010000001110110110010100100100100100
000110011010001000000110110000010000001010110011011011011001
000000011010010010010001000000111011011011101001001001000110
110110010100100101011001000100000011010001000000111011011001
010010010010010001101101101001000110110010110001101101101101
100100010001010010001010011011001000000011001101001001010010
000001100101001000111

Это следующая программа BrainFuck, преобразованная в ложку:

-[+[+<]>>+]<+++.[->+>+<<]>>++>>,[>-[<->-----]+<+++[-<+<<.>>>>-<]>[-<<-[->+<]<<<[-]>>>>[-<+<<<+>>>>]<<.>>+<[>-]>[-<+<<.>>>>]<<>>]<,]<<<<[>.>.<<[-]]>>>+[-<.>]+

Читает целое число в двоичном формате на стандартный ввод и выводит вложенный список на стандартный вывод. Требуется 0 для ввода в качестве пустой строки (без цифр), а также требуется интерпретатор мозгового штурма с 8-битными ячейками. Тот же алгоритм, что и мой ответ на Python.

Читаемая версия:

-[+[+<]>>+]<+++.           push open bracket and print it
[->+>+<<]                  dup
>>++                       increment to close bracket

>>,[                       read input loop
    >-[<->-----]+<+++          subtract 48 and set up if/else
    [-                         if c == 1
        <+                         increment s
        <<.>>>                     output open bracket
    >-<]>[-<                   else
        <-[->+<]                   decrement and move s
        <<<[-]                     zero l
        >>>>[-<+<<<+>>>>]          l = s and restore s
        <<.>                       output close bracket
        >+<[>-]>[-                 if s == 0
            <+                         undo s decrement
            <<.                        output open bracket
        >>>>]<<
    >>]<
,]

<<<<[                      if l
    >.>.                   output pair
<<[-]]
>>>+[-<.>]                 output close bracket s+1 times

3
Недавно мы обсуждали другой ответ, и, похоже, нет реального интерпретатора, который мог бы обрабатывать 63-байтовый файл. В эталонной реализации использовались байты 0x30 и 0x31, поэтому для этого ответа потребуется файл размером 501 байт .
Деннис


5

Perl, 80 79 байтов

Снова использует алгоритм orlp , но на этот раз я впервые проверил, работает ли он ...

Включает +1 для -p

Дайте номер ввода на STDIN

nest.pl <<< 8

nest.pl:

#!/usr/bin/perl -p
($_=sprintf"%b",$_).=2x(s^.^$&or++$n-pos&&/.0/g?++$n%1:$`&&21^eg-$n);y;102;();

Решение Линуса составляет 64 байта в perl:

#!/usr/bin/perl -p
$_=sprintf"%b",/.+/g;$_=10x($&&&$&+16)if!/^(1(?1)*0)+$/;y;10;()

Решение Денниса составляет 59 байтов в perl (для больших чисел все медленнее):

#!/usr/bin/perl -p
1while$_-=(sprintf"%b",$n++)=~/^(1(?1)*0)+$/;$_=$&;y;10;()

Я чувствую, что вы должны просто оценить это как 65 байт (не правда ли, 64)?
Линус

1
@Linus Хотя ваши уклонения от правил блестящие и заслуживают всех положительных отзывов, я считаю это немного обманом. За подсчет -pсчитается 1 дополнительный байт
Ton Hospel

5

Python 3, 120 114 байт

def f(n,k=0):
 while~n:
  k+=1
  try:r=eval(bin(k).translate({48:'],',49:'['})[3:-1])+[];n-=1
  except:0
 print(r)

Проверьте это на Ideone .

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

Определенная функция f принимает входные данные n и инициализирует k как 0 . Мы будем увеличивать k до тех пор, пока n + 1 значений k не приведет к правильному выводу. Каждый раз, когда мы находим такое значение k , n уменьшается при достижении -1 , ~nвозвращает 0 и печатается список r, который соответствует последнему значению k .

Частичное отображение из натуральных чисел во вложенные списки (т. Е. K k r ) должно быть биективным, но других ограничений нет. Тот, который используется в этом ответе, работает следующим образом.

  1. Преобразовать k в двоичное строковое представление, начиная с 0b .

    Например, 44 ↦ "0b101100" .

  2. Замените все 0 (кодовая точка 48 ) в строковом представлении на строку "], а все 1 (кодовая точка 49 ) на [ .

    Например, "0b101100" ↦ "], b [], [[],]," .

  3. Удалите первые три символа (они соответствуют "0b" ) и завершающий символ (возможно, запятую).

    Например, "], b [], [[],]," ↦ "[], [[],]" .

  4. Попробуйте оценить сгенерированный код. Если это приводит к ошибке, k не отображается ни в один список.

    Например, «[], [[],]» ↦ ([], [[]]) .

  5. Объединить результат (если есть) с пустым списком. Если это приводит к ошибке, k не отображается ни в один список.

    Например, ([], [[]]) + [] ошибки, поскольку + не может объединять списки и кортежи.


4

Haskell, 71 байт

p 1=["[]"]
p n=['[':h++t|k<-[1..n-1],h<-p k,_:t<-p$n-k]
((p=<<[1..])!!)

Основная функция в последней строке индексирует в список всех вложенных массивов, отсортированных по размеру (количеству открытых скобок). Итак, все массивы размером не более 16 перечислены первыми.

Давайте сначала посмотрим на код, который приятнее и короче, но проверка типов в Haskell отказывается его принимать.

p 1=[[]]
p n=[h:t|k<-[1..n-1],h<-p k,t<-p$n-k]
((p=<<[1..])!!)

Функция pна входе nдает список всех вложенных массивов размера n(открытые скобки). Это делается рекурсивно. Каждый такой массив состоит из некоторой головы h(первого члена) размера kи некоторого хвостаt (других членов) n-k, причем оба размера отличны от нуля. Или это пустой массив для размера n==1.

Выражение p=<<[1..]затем выравниваетсяp(1), p(2), ... в один бесконечный список всех массивов, отсортированных по размеру.

[ [], [[]], [[],[]], [[[]]], [[],[],[]], [[],[[]]], [[[]],[]], [[[],[]]], ...

и главная функция указывает на это.

... Или, если бы Хаскелл не скулил о "построении бесконечного типа: t ~ [t]". Haskell не может представлять бесконечный список, над элементами которого являются произвольно вложенные массивы. Все его элементы должны иметь одинаковый тип, но тип t не может совпадать со списком t. На самом деле, функцияp нельзя присвоить согласованный тип без зависимой типизации, чего нет у Haskell.

Таким образом, вместо этого мы работаем со строками скобок, моделируя операцию cons, воздействуя на символы [и ]символы. Это занимает дополнительные 9 байтов. Опасности игры в гольф на безопасном языке.


3

Haskell, 87 82 байта

0#0=[""]
n#m=['[':x|n>0,x<-(n-1)#m]++[']':x|n<m,x<-n#(m-1)]
(([0..]>>= \y->y#y)!!)

Выводит элементы массива. Пример использования: (([0..]>>= \y->y#y)!!) 3-> "[][]".

Функция #строит все вложенные массивы как строки для nоткрытых и mзакрытых скобок, отслеживая, сколько из них осталось. Всегда начинается с n == m. Основная функция вызывает y # yдля каждого y <- [0,1,...]и выбирает элемент по индексу, указанному на входе.


2

MATL , 31 байт

O`@BEqXJYs0&)0>w~hA+tG>~]x92J-c

Попробуйте онлайн! Или проверьте первые несколько тестовых случаев (занимает несколько секунд).

Произведенное отображение:

0 -> []
1 -> [[]]
2 -> [[][]]
3 -> [[[]]]
4 -> [[][][]]
5 -> [[][[]]]
6 -> [[[]][]]
7 -> [[[][]]]
...

объяснение

Код продолжает тестировать увеличивающиеся двоичные числа, с 0заменой цифры на -1; то есть используя 1и -1как цифры. Цифра 1будет представлять '['и -1будет представлять']' .

Программа считает до n +1 действительных чисел. Номер действителен, если выполняются следующие два условия:

  1. Сумма цифр равна нулю (то есть, есть равное количество 1и-1 )
  2. Кумулятивная сумма цифр всегда положительна (то есть накопленное количество 1цифр всегда превышает цифру -1), кроме как в конце (где она равна нулю по условию 1).

После получения n +1 действительных чисел последнее транслитерируется путем перехода 1в [и -1в] , а затем отображается.

Код:

O          % Push 0: initial count of valid numbers
`          % Do...while
  @        %   Push iteretation index k, starting at 1
  B        %   Convert to binary. For example, k=6 gives [1 1 0 0]
  Eq       %   Multiply by 2, subtract 1: transforms [1 1 0 0] into [1 1 -1 -1]
  XJ       %   Copy that to clipboard J, without popping it
  Ys       %   Cumulative sum: gives [1 2 1 0]
  0&)      %   Split array into its final element and the rest. Gives 0, [1 2 1]
  0>       %   Yields 1 for positive entries (condition 2). So in this case it
           %   gives [1 1 1]
  w        %   Swap: moves second-top element in the stack (0 in this case) to top
  ~        %   Negate: yields 1 if input is 0 (condition 1). Gives 1 in this case
  h        %   Concatenate horizontally. Gives [1 1 1 1]
  A        %   All: gives 1 if all elements are 1. Gives 1 in this case, meaning
           %   that this k is valid
  +        %   Add the result (0 or 1) to the count of valid numbers
  t        %   Duplicate
  G        %   Push input n
  >~       %   Loop condition: false (exit loop) if count exceeds input n
]          % End loop. At this point the result is in clipboard J, in 1/-1 format
x          % Delete count
92         % Push 92. Will be used to convert 1, -1 to '[', ']' (ASCII 91, 93)
J          % Push result in 1/-1 format
-          % Subtract: converts 1 to 91, -1 to 93
c          % Convert to char. Implicitly display
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.