Выходные числа до 2 ^ n-1, «отсортированные»

38

Возьмите положительное целое число n в качестве входных данных и выведите (некоторые из них) десятичные числа, которые можно создать с использованием n битов, упорядоченных следующим образом:

Сначала перечислите все числа, которые могут быть созданы только с одним 1, а остальные 0в двоичном представлении (отсортированы), затем все числа, которые можно создать с двумя последовательными 1 , остальные 0, затем три последовательных 1 и так далее.

Посмотрим, как это выглядит при n = 4 :

0001  -  1
0010  -  2
0100  -  4
1000  -  8
0011  -  3
0110  -  6
1100  -  12
0111  -  7
1110  -  14
1111  -  15

Таким образом, выходные данные для n = 4 : 1, 2, 4, 8, 3, 6, 12, 7, 14, 15 (необязательный формат вывода).

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

n = 1
1

n = 2
1 2 3

n = 3
1, 2, 4, 3, 6, 7

n = 8
1, 2, 4, 8, 16, 32, 64, 128, 3, 6, 12, 24, 48, 96, 192, 7, 14, 28, 56, 112, 224, 15, 30, 60, 120, 240, 31, 62, 124, 248, 63, 126, 252, 127, 254, 255

n = 17
1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 3, 6, 12, 24, 48, 96, 192, 384, 768, 1536, 3072, 6144, 12288, 24576, 49152, 98304, 7, 14, 28, 56, 112, 224, 448, 896, 1792, 3584, 7168, 14336, 28672, 57344, 114688, 15, 30, 60, 120, 240, 480, 960, 1920, 3840, 7680, 15360, 30720, 61440, 122880, 31, 62, 124, 248, 496, 992, 1984, 3968, 7936, 15872, 31744, 63488, 126976, 63, 126, 252, 504, 1008, 2016, 4032, 8064, 16128, 32256, 64512, 129024, 127, 254, 508, 1016, 2032, 4064, 8128, 16256, 32512, 65024, 130048, 255, 510, 1020, 2040, 4080, 8160, 16320, 32640, 65280, 130560, 511, 1022, 2044, 4088, 8176, 16352, 32704, 65408, 130816, 1023, 2046, 4092, 8184, 16368, 32736, 65472, 130944, 2047, 4094, 8188, 16376, 32752, 65504, 131008, 4095, 8190, 16380, 32760, 65520, 131040, 8191, 16382, 32764, 65528, 131056,16383, 32766, 65532, 131064, 32767, 65534, 131068, 65535, 131070, 131071

Это , поэтому выигрывает самый короткий код на каждом языке !

Хорошие объяснения приветствуются , в том числе и для решений на «обычных языках»!

Стьюи Гриффин
источник
2
@zeppelin Сначала я тоже так думал, но этот совсем другой.
ETHproductions
1
Связанный. (Немного.)
Мартин Эндер
6
Воображаемый бонус, если кто-то делает это без какой-либо базовой конверсии (используя простую старую математику).
Стьюи Гриффин
Написал это, что является смесью между двумя, я думаю, Попробуйте онлайн!
PrincePolka

Ответы:

38

Python , 53 байта

f=lambda n,i=1:n*[f]and[i]+f(n-1,2*i)+i%2*f(n-1,i-~i)

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

Рекурсивная функция генерирует отсортированный список как предварительный порядок перехода по этому дереву (пример с n=4):

      1
     / \
    2   3
   /   / \
  4   6   7
 /   /   / \
8   12  14  15

1 2 4 8 3 6 12 7 14 15

Левые ветви удваивают значение, а правые ветви i->i*2+1существуют и существуют только для нечетных i. Итак, предварительный заказ на не-листья есть T(i)=[i]+T(i*2)+i%2*T(i*2+1).

Дерево заканчивается на глубине n, где nнаходится вход. Это достигается уменьшением nс каждым шагом вниз и остановкой, когда он равен 0.

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

f=lambda n,i=1:2**n/i*[f]and[i]+f(n,2*i)+i%2*f(n,i-~i)
f=lambda n,i=1:[f][i>>n:]and[i]+f(n,2*i)+i%2*f(n,i-~i)
XNOR
источник
4
Вау. Это не только крутой / умный трюк, но и чрезвычайно эффективный. +1, действительно хороший ответ!
DJMcMayhem
2
Это [f]забавное прикосновение, не могу сказать, что видел это раньше.
FryAmTheEggman
18

Желе , 6 байт

Ḷ2*ẆS€

Это дает право на мнимый бонус .

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

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

Ḷ2*ẆS€  Main link. Argument: n

Ḷ       Unlength; yield [0, ..., n-1].
 2*     Yield [2**0, ..., 2**(n-1)].
   Ẇ    Sliding window; yield all subarrays of consecutive elements.
        The subarrays are sorted by length, then from left to right.
    S€  Map the sum atom over the substrings.
Деннис
источник
1
является идеальным встроенным решением для этой задачи, и оно реализовано таким образом, что результаты находятся в правильном порядке для этой задачи. Хорошо сделано :-)
ETHproductions
Разве это не 12 байтов (по крайней мере, в UTF-8)?
Гарет
1
@Gareth Да, но Jelly также поддерживает однобайтовый набор символов , который содержит только 256 символов, которые он понимает.
Деннис
9

Mathematica, 40 байт

Join@@Table[2^j(2^i-1),{i,#},{j,0,#-i}]&

Каждое число в желаемом списке является разностью двух степеней 2, поэтому мы просто генерируем их по порядку, используя, Tableа затем выравниваем список. Я думаю, что это зарабатывает воображаемый бонус Стьюи Гриффин :)

Mathematica, 35 байт

Tr/@Rest@Subsequences[2^Range@#/2]&

Порт Денниса алгоритм Желе . Я не знал об Subsequencesэтом до этого! (Я также не видел, чтобы мили опубликовали этот точный ответ ... иди, проголосуй!)

Грег Мартин
источник
1
Примечание. Это решение идентично коду Mathematica @mile , опубликованному за 5 часов до редактирования @GregMartin. Однако, согласно мета-консенсусу , этот ответ остается в силе.
JungHwan Мин
Тьфу, я этого не видел - спасибо, что указал на это.
Грег Мартин
8

JavaScript (ES6), 59 58 55 байт

for(q=prompt(n=1);p=q--;n-=~n)for(m=n;p--;m*=2)alert(m)

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

Тестовый фрагмент

(Примечание: использует console.logвместо alert)

ETHproductions
источник
Предложение (после проверки «больше не показывать всплывающие окна»): перейдите на console.log для тестового фрагмента.
Теджас Кале
@TejasKale Хорошая идея, спасибо!
ETHproductions
7

JavaScript (ES6), 55 51 байт

Возвращает разделенный пробелами список целых чисел.

n=>(F=k=>k>>n?--j?F(k>>j|1):'':k+' '+F(k*2))(1,j=n)

Мнимый бонус дружелюбен.

Отформатировано и прокомментировано

n => (                    // main function, takes n as input
  F = k =>                // recursive function, takes k as input
    k >> n ?              // if k is greater or equal to 1 << n:
      --j ?               //   decrement j ; if j is > 0:
        F(k >> j | 1)     //     do a recursive call with an additional bit set
      :                   //   else
        ''                //     stop recursion
    :                     // else
      k + ' ' + F(k * 2)  //   append k to output and do a recursive call with k * 2
  )(1, j = n)             // start the recursion with k = 1 and j = n

Контрольные примеры

Arnauld
источник
6

Mathematica, 35 байт

Tr/@Rest@Subsequences[2^Range@#/2]&
миль
источник
5

Python 2 , 65 63 58 байт

lambda n:[(2<<k/n)-1<<k%n for k in range(n*n)if k/n+k%n<n]

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

Деннис
источник
1
Я потратил час на то, чтобы придумать эту формулу (2<<i)-1<<j... и вы уже поняли это. Отличная работа! Кроме того, хорошая работа по избавлению от двойных диапазонов
TheNumberOne
4

Haskell, 47 байтов

f n=[1..n]>>= \b->take(n-b+1)$iterate(2*)$2^b-1

Пример использования: f 4-> [1,2,4,8,3,6,12,7,14,15]. Попробуйте онлайн! ,

Как это работает: для каждого числа bв [1..n], начните с 2^b-1и повторно двойным значением и принимать n-b+1элементы из этого списка.

Ними
источник
4

Groovy, 90 89 байт

{(0..<2**it).collect{0.toBinaryString(it)}.sort{it.count("1")}.collect{0.parseInt(it,2)}}

Бинарное преобразование настолько тупо в заводной.

-1 спасибо Гурупаду Мамадапуру

Урна волшебного осьминога
источник
3
28 байт двоичного преобразования, так больно.
Волшебная Урна Осьминога
1
{(1..<2**it)...сохраняет байт.
Гурупад Мамадапур
3

Утилиты Bash + Unix, 51 байт

dc<<<2i`seq -f%.f $[10**$1-1]|grep ^1*0*$|sort -r`f

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

Ввод n передается в качестве аргумента.

Используйте seq для печати всех чисел с n или менее цифрами. (Это числа с базовыми 10, так что здесь много дополнительных чисел. Это расточительно и отнимает много времени, но это кодовый гольф!)

Призыв к grep сохраняет только те числа, которые состоят ровно из 1 с, а затем 0.

Затем используйте sort -r, чтобы отсортировать их в обратном лексикографическом порядке.

Наконец, dc устанавливается на вход base 2 - он помещает отсортированные числа в стек, а затем печатает стек сверху вниз. (Это печатает последний элемент, помещенный первым, и т. Д., Поэтому я использую сортировку -r вместо просто сортировки.)

Исправлена ​​ошибка: я опустил опцию -f% .f в seq, которая требуется для целых чисел от 1000000 и далее. (Спасибо @TobySpeight за указание на проблему.)

Митчелл Спектор
источник
" Расточительный и трудоемкий " ... и умный ! Спасибо за это - это хорошее напоминание о намеренном игнорировании вычислительной эффективности при игре в гольф. Это действительно тяжело, когда ты проводишь остаток своих дней за написанием быстрого и понятного кода ...
Тоби Спейт
Некоторые значения отсутствуют: dc<<<2i`seq $[10**7-1]|grep ^1*0*$|sort -r`f | wc -только сообщает 12 значений. Я думаю, что вы хотите grep ^1[01]*$вместо этого.
Тоби Спейт
@TobySpeight Спасибо - произошла ошибка, которую я исправил. Проблема была не с регулярным выражением; проблема заключалась в том, что для seq требовалась опция. (Я не уверен, почему вы получали только 12 выходных значений - даже неправильная версия вызвала 21 выходное значение вместо правильного 28. Если вы работали с этим на TIO, возможно, оно превысило 1-минутное ограничение TIO .) Теперь я проверил это на Linux и OS X.
Митчелл Спектор
1
На самом деле, я неправильно понял вопрос - важное слово «последовательный» как-то пролетело мимо меня!
Тоби Спейт
2

Perl 6 , 38 байт

->\n{map {|(2**$_-1 X+<0..n-$_)},1..n}

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

->\n{                                }  # A lambda with argument n.
                                 1..n   # Numbers from 1 to n.
     map {                     },       # Replace each one with a list:
            2**$_-1                     #   2 to that power minus 1,
                    X+<                 #   bit-shifted to the left by each element of
                       0..n-$_          #   the range from 0 to n minus the number.
          |(                  )         #   Slip the list into the outer list.

Т.е. он строит числа вот так:

1 2 4 8 = (2^1)-1 bit-shifted to the left by 0 1 2 3 places
3 6 12  = (2^2)-1 bit-shifted to the left by 0 1 2   places
7 14    = (2^3)-1 bit-shifted to the left by 0 1     places
15      = (2^4)-1 bit-shifted to the left by 0       places      n rows
                                                  
             n                                     n-1

Код:


Perl 6 , 44 байта

->\n{map {|(2**$_-1,* *2...^*>2**n-1)},1..n}

Это был мой первый подход, прежде чем я подумал о (на самом деле более простом) решении с битовым сдвигом выше.

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

->\n{                                      }  # A lambda with argument n.
                                       1..n   # Numbers from 1 to n.
     map {                           }        # Replace each one with:
            2**$_-1                              # 2 to that power minus 1,
                   ,* *2                         # followed by the result of doubling it,
                        ...^                     # repeated until (but not including)
                            *>2**n-1             # it's larger than 2^n-1.
          |(                        )            # Slip the list into the outer list.

Т.е. он строит числа вот так:

1 2 4 8 = (2^1)-1, times 2, times 2, times 2
3 6 12  = (2^2)-1, times 2, times 2
7 14    = (2^3)-1, times 2
15      = (2^4)-1                                 n rows
                                    
             n                       as many columns as possible in
                                     each row without exceeding (2^n)-1
SMLS
источник
2

Haskell 59 46 байт

Я начал с f n=[0..n]>>= \b->take(n-b).iterate(*2).sum.map(2^)$[0..b]

от ответа Ними выше получил понимание, которое sum.map(2^)$[0..x]может быть сведено к2^x-1

Заканчивая с

e n=[1..n]>>= \x->map(\y->2^y*(2^x-1))[0..n-x]

[1..n] - список с количеством последовательных битов, которые мы хотим пролистать`

>> = - полностью переведенный для каждого элемента в списке слева, передать его в функцию справа и объединить все результаты

\ x -> - объявление лямбда-функции с одним аргументом

map xy - применяет функцию x ко всем членам списка y

В нашем случае x = (\ y-> 2 ^ y * (2 ^ x-1)) - другая лямбда-функция 2 ^ y * (2 ^ x-1)). Эта формула возникает из умножения на два, добавляя ноль вправо в двоичном виде (например, с 0001 по 0010). 2 ^ x - 1 - это количество бит, с которыми мы работаем. поэтому для 11 у нас есть 2 ^ 0 * 3 (т.е. вообще не сдвигаться) == 0011, затем 2 ^ 1 * 3 = 0110, затем 2 ^ 2 * 3 - 1100.

[0..nx] Составляет список того, сколько раз мы можем сдвинуть биты. Если мы работаем с одним 1, то, глядя на 0001, мы хотим сместить 3 раза (4-1). Если мы работаем два 11, мы хотим 4-2 и так далее.

брендер
источник
2

Python 3, 59 байт

Примечание: это было сделано независимо от решений ovs и Dennis , хотя это очень похоже на оба.

lambda n:[(2<<i)-1<<j for i in range(n)for j in range(n-i)]

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

for i in range(n)for j in range(n-i)  # Iterate over number of ones, then number of places
                                      # shifted over. i = ones, j = shifts

(2<<i)                                # Create a one followed by i zeroes
      -1                              # Subtract one from above to get i ones.
        <<j                           # Shift j places.

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

Советы (как кодирование, так и наличные) всегда приветствуются!

Номер один
источник
2

Japt , 11 байт

o@o!²ãXÄ mx

Проверьте это онлайн!

объяснение

Это в значительной степени использует подход @ Dennis:

o@ o!²  ãXÄ  mx
oX{o!p2 ãX+1 mx}
                  // Implicit: U = input integer
oX{            }  // Create the range [0...U) and map each item X by this function:
   o              //   Create the range [0...U)
    !p2           //     and map each item Z to 2.p(Z); that is, 2**Z.
                  //     (p2 would map each item Z to Z.p(2); ! reverses the arguments.)
        ãX+1      //   Get all overlapping slices of length X + 1.
             mx   //   Map each of these slices Z through Z.x(); that is, sum each slice.
                  // Implicit: output result of last expression
ETHproductions
источник
2

PHP, 59 56 53 байта

for(;$p>($k*=2)?:($p=1<<$argn)>$k=$i+=$i+1;)echo$k,_;

принимает данные от STDIN; беги с -R.

сломать

for(;$p>($k*=2)         // 3. inner loop: shift-0 $k while $k<$p (false in first iteration)
    ?:
    ($p=1<<$argvn)      // 1. init $p=2^N, outer loop:
    >$k=$i+=$i+1        // 2. shift-1 $i while $i<$p, init $k to new $i
;)
    echo$k,_;           // 4. print $k
Titus
источник
Вы можете использовать $argnочень хорошую идею. После прочтения вопроса у меня в голове есть решение с более чем 200
байтами
@ JörgHülsermann Спасибо, что напомнили мне о STDIN. Я просто люблю слияние петель.
Титус
1

J , 19 байт

(0-.~&,>:+/\2&^)@i.

При этом используется тот же метод в @Dennis' растворе .

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

объяснение

(0-.~&,>:+/\2&^)@i.  Input: integer n
                 i.  Range [0, 1, ..., n-1]
(              )@    Operate on that range
            2&^        Compute 2^x for each x in that range
       >:              Increment each in that range
           \           For each overlapping sublist of size (previous) in powers of 2
         +/              Reduce by addition
 0                     The constant 0
     &,                Flatten each
  -.~                  Remove zeroes
миль
источник
1

Python 3, 91 байт

a=int(input())
print(*[int('1'*-~b,2)<<c for b in range(a)for c in range(a-b)],sep=', ')

Полная программа с выводом через запятую + пробел, как указано.

Объяснение:

Звездная нотация распаковывает списки. Так print(*[1,2,3])же, как print(1,2,3). Передайте int()конструктору строку последовательных 1.

-~bоценивает b+1, но вам не нужно заключать его в квадратные скобки при умножении строки.

Сдвиг полученного целого числа все большее число раз. print()имеет необязательный аргумент sep, указывающий строку для вставки между каждым элементом в распакованном списке.

mypetlion
источник
2
Вы можете просто распечатать список. Формат вывода не такой строгий.
mbomb007,
1

Java 7, 108 байт

static void x(int i){int a=0,t=1<<i,b;while((a=(a<<1)+1)<t){b=a;do System.out.println(b);while((b<<=1)<t);}}

Удваивает начальное значение, если результат меньше, чем 2^n. После этого обновляет начальное значение, чтобы быть (initial_value * 2) + 1и начинается снова оттуда, пока оно в конечном итоге не достигнет (2^n)-1.

например для n=4:

0001 -> init
0010
0100
1000
return, double init and add one
0011 -> init
0110
1100
return, double init and add one
0111 -> init
1110
return, double init and add one
1111 -> init
done

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

QBrute
источник
1

Рубин, 50 байтов

->r{1.upto(r){|x|p a=2**x-1;p a while(a*=2)<2**r}}

Я попробовал некоторые «умные» подходы, но это, кажется, самый короткий (буквально следуйте инструкциям)

Объяснение:

Каждая итерация начинается с 2 ^ n-1 и умножается на 2, пока не будет достигнут верхний предел. Ничего особенного, просто базовая математика.

гигабайт
источник
1

QBIC , 37 байт - мнимый бонус = еще 37 байт ...

:[a|e=2^b-1┘while e<2^a┘?e┘e=e*2┘wend

Жаль, что я еще не встроил while-wendв QBIC ... Объяснение:

:       Get N from the command line
[a|     For b = 1 to N; The sequence is reset N times
e=2^b-1 Set the first number of this sub-sequence (yields 1, 3, 7, 15 ...)
┘       Line-break - syntactic separation of commands because there's no command for WHILE yet.
while   Pure QBasic code - lower-case is not (really) interpreted by QBIC
e<2^a   Continue as long as we don't exceed the maximum value
┘?e     Print the number in the sequence
┘e=e*2  Double the number
┘wend   And loop as long as we're not exceeding maximum, reset the sequence otherwise.
        FOR loop auto-closed by QBIC

РЕДАКТИРОВАТЬ: QBIC теперь имеет поддержку для WHILE:

:[a|e=2^b-1≈e<2^a|?e┘e=e*2

Это всего 26 байтов! Вот это WHILE:

≈e<2^a|          ≈ = WHILE, and the TRUE condition is everything up to the |
       ...       Loop code goes here
          ]      Close construct: adds a WEND instruction
                 In the program above, this is done implicitly because of EOF.
steenbergh
источник
1

R , 69 48 46 байт

n=scan();for(i in 1:n)print((2^i-1)*2^(i:n-i))

Каждое десятичное число, соответствующее i in 1..nединице в двоичной системе, умножается на 2^(0..n-i), то есть первые n-i+1степени двух (1, 2, 4, ...).

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

Роберт Хакен
источник
1

Stax , 9 байт

übg▓}╥é►╪

Запускать и отлаживать онлайн!

объяснение

Воображаемый бонус, если кто-то делает это без какой-либо базовой конверсии (используя простую старую математику).

Ну, здесь нет базового преобразования.

Используется распакованная версия (10 байт) для объяснения.

m|2vx_-DQH
m             For input=`n`, loop over `1..n`
 |2v          Power of two minus one
    x_-D      Do `n-j` times, where `j` is the current 1-based loop index
        Q     Output the current value
         H    And double it
Вейцзюнь Чжоу
источник
0

Пакетная, 92 - 0 = 92 байта

@for /l %%i in (1,1,%1)do @for /l %%j in (%%i,1,%1)do @cmd/cset/a"(1<<%%i)-1<<%%j-%%i"&echo(

Вычитая 0 для мнимого бонуса @ StewieGriffin.

Нил
источник