Від 0 до 2 ^ n - 1 у порядку POPCORN


18

... Ах вибачте, тут немає попкорну, просто POPCNT.

Напишіть найкоротшу програму або функцію, яка бере число nі виведете всі цілі числа від 0 до 2 n - 1, у порядку зростання числа 1 біт у двійковому поданні чисел (popcount). Дублікати не дозволені.

Порядок номерів з однаковими попконтатами визначається реалізацією.

Наприклад, для n = 3всіх цих результатів дійсні:

0, 1, 2, 4, 3, 5, 6, 7
[0, 4, 1, 2, 5, 3, 6, 7]
0 4 2 1 6 5 3 7 

Формат введення та виведення визначається реалізацією, що дозволяє використовувати мовні функції для подальшого гольфу коду. Існує кілька обмежень на вихід:

  • Цифри повинні виводитися у десятковому форматі.
  • Вихід повинен містити розумний роздільник між числами (дозволений тривалій роздільник, але не ведучий).

    Лінія подачі ( \n), вкладка ( \t), простір, ,, ., ;, |, -, _, /цілком розумні сепаратор. Я не проти додаткових пробілів для гарного друку, але не використовуйте літери чи цифри як роздільники.

  • Номери та сепаратори можуть бути оточені [ ], { }або будь-якого масиву або списку позначень.
  • Не друкуйте нічого іншого, не зазначеного вище.

Бонус

Помножте свій результат на 0,5 якщо ваше рішення може генерувати число під час руху. Дух цього бонусу полягає в тому, що якщо ви повинні безпосередньо перетворити рішення для друку в генератор, генератор використовує лише максимум O (n) пам'яті, де n - кількість бітів, як визначено вище. (Вам не потрібно насправді перетворювати рішення в генератор). Зауважте, що, хоча я накладаю n <= 28, пам'ять, необхідна для зберігання всіх чисел, все ще зростає експоненціально, і наївне рішення для сортування дозволило б накопичити щонайменше 4 ГБ пам'яті при n = 28.

Додайте кілька простих пояснень того, як працює ваше рішення, перш ніж вимагати цього бонусу.


4
Здається, що виклик, як це досить нудно, і призведе до купі сортування відповідей. Я хотів би додати трохи бонусу, щоб зробити виклик цікавішим. Щось уздовж лінії "генерування чисел на льоту". Якщо з вами все гаразд, будь ласка, відправте цей коментар, тоді я додам його до питання.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

Якщо ви не згодні, будь ласка, підтримайте цей коментар.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

Будь ласка, використовуйте пісочницю, щоб подати додаткові пропозиції щодо цього питання, перш ніж публікувати його в прямому ефірі.
Джон Дворак

21
@JanDvorak: Це було на пісочниці один місяць.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

1
Я думаю, що для цього питання вже пізно. Взагалі, на мою думку, питання, де ви повинні з'ясувати нетривіальний алгоритм, не дуже підходять для кодового гольфу. Зробіть замість них виклик коду та поставте всі необхідні обмеження.
FUZxxl

Відповіді:



7

Пітон 2, 75 * 0,5 = 37,5

N=2**input()-1
v=N-~N
while v:t=1+(v|~-v);v=N&t|~-(t&-t)/(v&-v)/2;print v^N

Повторно генерує наступний найвищий показник vз тим самим POPCOUNT за допомогою цього алгоритму роздвоєння бітів .

Насправді, виявилося простіше створити їх у зменшенні кількості попсів, а потім надрукувати додаток, щоб зробити його збільшенням. Таким чином, потім vпереповнюючи 2**n, ми просто видаляємо всі, крім nбітів, &NдеN=2**n-1 і, що дає найменший попконт номер один нижче. Таким чином, ми можемо зробити лише одну петлю. Мабуть, краще рішення, яке безпосередньо знаходить наступне нижнє число з тим же POPCOUNT.

Через проблему з забором, нам потрібно почати v=2**(n+1)-1 того, щоб операція вироблялася v=N-1на першому циклі.

Вихід для 4:

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

Не потрібно збільшувати кількість таких же попконтів. Порядок визначено реалізацією.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

1
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Я знаю, але я не бачу, як врятувати персонажів, роблячи це по-іншому.
xnor

Наївним методом з 3-х циклів я набираю майже те саме в JS (маючи console.log()vs print). Можливо, біт трюк занадто важкий.
edc65

Економія на один байт:v=N-~N
Sp3000

5

J, 19 символів, бонусу немає.

[:(/:+/"1@#:)@i.2^]
  • 2 ^ y- два на владу y.
  • i. 2 ^ y- цілі числа від 0до (2 ^ y) - 1.
  • #: i. 2 ^ y - кожне з цих цілих чисел, представлених у базі другого.
  • +/"1 #: i. 2 ^ y - суми кожного представництва
  • (i. 2 ^ y) /: +/"1 #: i. 2 ^ y- вектор, i. 2 ^ yвідсортований за порядком елементів попереднього вектора, наша відповідь.

3

Пітона, 63 символи

F=lambda n:`sorted(range(1<<n),key=lambda x:bin(x).count('1'))`

>>> F(3)
'[0, 1, 2, 4, 3, 5, 6, 7]'

@Alex: У списку обмежень мається на увазі, що він хотів отримати рядковий результат.
Кіт Рендалл

Вибачте, пропустив це.
Олексій А.

3

C 179 * 0,5 = 89,5

main(){int n,i=0,m,o;scanf("%d",&n);m=~((~0)<<n);for(;n--;++i){for(o=0;o<m;++o){int bc=0,cb=28;for(;cb--;)bc+=o&(1<<cb)?1:0;if(bc==i)printf("%d ",o);}}printf("%d\n",m);return 0;}

РЕДАКТ: 157 * 0,5 = 78,5

main(){int n,i=0,m,o;scanf("%d",&n);m=~((~0)<<n);for(++n;n--;++i){for(o=0;o<=m;++o){int bc=0,cb=28;for(;cb--;)bc+=o&(1<<cb)?1:0;if(bc==i)printf("%d ",o);}}}

РЕДАКТ: 132 * 0,5 = 66

main(){int n,i=0,m,o;scanf("%d",&n);m=~((~0)<<n);for(++n;n--;++i){for(o=0;o<=m;++o){if(__builtin_popcount(o)==i)printf("%d ",o);}}}

або трохи приємніше відформатовано:

main()
{
    int n, i = 0, m, o;
    scanf("%d", &n);
    m = ~((~0) << n);
    for(++n; n--; ++i)
    {
        for(o = 0; o <= m; ++o)
        {
            if (__builtin_popcount(o) == i)
                printf("%d ", o);
        }
    }
}

Що це робить?

m = ~((~0) << n);

обчислює останнє число для показу (pow (2, n) - 1)

    for(++n; n--; ++i)
    {
        for(o = 0; o <= m; ++o)
        {

зовнішня петля перетворюється на кількість бітів (так 0 до n-1), тоді як внутрішня петля нараховує від 0 до m

            if (__builtin_popcount(o) == i)
                printf("%d ", o);

На x86 є інструкція POPCNT, яку можна використовувати для підрахунку встановлених бітів. GCC та сумісні компілятори можуть підтримувати функцію __builtin_popcount, яка в основному компілюється в цій інструкції.




1

JavaScript (ES6) 41 (82 * 0,5)

Найпростіший спосіб - гольф

F=b=>{
  for(l=0;l<=b;l++)
    for(i=1<<b;i;t||console.log(i))
      for(t=l,u=--i;u;--t)
        u&=u-1;
}

Безумовно

F=b=>
{
  for (l = 0; l <= b; l++)
  {
    for (i = 1 << b; i > 0; )
    {
      --i;
      for (t = 0, u = i; u; ++t) // Counting bits set, Brian Kernighan's way
        u &= u - 1;
      if (t == l) console.log(i);
    }
  }
}

Тест на консолі Firefox / FireBug

F(4)

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


1

Bash + coreutils, 66

Для початку:

jot -w2o%dpc $[2**$1] 0|dc|tr -d 0|nl -ba -v0 -w9|sort -k2|cut -f1

Тут нічого насправді не захоплюючого. З огляду на ваш коментар, я з радістю видалю / переглянути цю відповідь, якщо ви хочете змінити питання.
Цифрова травма

Не впевнений, якщо я повинен виділити, що ваша програма повинна працювати для всіх значень n від 0 до 28 включно. Я не знаю, скільки відповідей тут відповідає цій вимозі.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

Я вилучив цю статтю, оскільки люди, схоже, її не помічають.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Зараз, теоретично, принаймні це повинно працювати до 28. Я перевірив до 22, але, звичайно, це sortпотребує тривалого часу. З n = 28, sortпотрібно буде сортувати 2 ^ 28 рядків / ~ 13 ГБ даних.
Цифрова травма

1

Хаскелл, (87 * 0,5) = 43,5

f n=[0..n]>>=(\x->x#(n-x))
a#0=[2^a-1]
0#_=[0]
a#b=[1+2*x|x<-(a-1)#b]++[2*x|x<-a#(b-1)]

Приклад використання:, f 4який виводить[0,1,2,4,8,3,5,9,6,10,12,7,11,13,14,15]

Як це працює: ні сортування, ні повторне повторення [0..2 ^ n-1] та пошук чисел, що містять i 1s.

У #функції помічника приймає два параметри aі bта формує список кожного числа, що складаються з a1s і b0s. Основна функція fвимагає #для кожної комбінації aта, bде a+bдорівнює n, починаючи з 1s та n0s, щоб мати порядкові числа. Завдяки ліні Хаскелла всі ці списки не повинні складатись повністю на пам’ять.


Має ледве не ++в a#bозначають , що ліва рука (яка може бути великим) повинен бути виконаний повністю , а потім копіюється перед першим елементом в результаті виходить, порушивши тим самим вимоги до бонусом?
Жуль

Ах, ні, якщо подумати про це, все ще можна ліниво генерувати їх під час їх виготовлення, потрібно просто зробити копію кожного предмета, який як обидва, так і сміття, зібрані під час обробки, означає, що використання місця є постійним. Ігноруй мене.
Жуль

1

Рубін 47 годин

Так само, як і Python від @KeithRandall:

f=->n{(0..1<<n).sort_by{|x|x.to_s(2).count ?1}}

1

Математика, 26

Tr/@(2^Subsets@Range@#/2)&

Приклад:

Tr/@(2^Subsets@Range@#/2)&[4]

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


0

Перл, 64/2 = 32

#!perl -ln
for$i(0..$_){$i-(sprintf"%b",$_)=~y/1//||print for 0..2**$_-1}

Просто повторіть діапазон [0..2^n-1] n + 1разів. У кожній ітерації друкуйте лише числа, що мають кількість 1 біт, рівну змінній ітерації ( $i). Біти підраховуються підрахунком 1s ( y/1//) у кількості, перетвореній у двійковий рядок, з sprintf.

Випробуй мене .

Перл, 63

Підхід до сортування:

#!perl -l
print for sort{eval+(sprintf"%b-%b",$a,$b)=~y/0//dr}0..2**<>-1

1
@Optimizer, Він використовує O (1) пам'ять. Яке ще визначення ми маємо? На жаль, це неправда, оскільки я друкую його в прямому ефірі :)
nutki

@Optimizer, виправлено.
nutki

Ну, я знаю про це, коли встановлюю умову, але я це все одно дозволяю, оскільки я хочу бачити, які заплутані відповіді люди можуть придумати.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

2
Я просто запитав "як", оскільки я не можу прочитати perl :) Хочете додати більше пояснень?
Оптимізатор

@Optimizer, додано ще одне пояснення.
нутки

0

Ява 8, 205

public class S{public static void main(String[] n){java.util.stream.IntStream.range(0,1<<Integer.parseInt(n[0])).boxed().sorted((a,b)->Integer.bitCount(a)-Integer.bitCount(b)).forEach(System.out::print);}}

0

C ++ 11, 117 символів:

using namespace std;int main(){ set<pair<int,int> > s;int b;cin>>b;int i=0;while(++i<pow(2,b))s.insert({bitset<32>(i).count(),i});for (auto it:s) cout <<it.second<<endl;}

Безголівки:

using namespace std;
int main()
{
    set<pair<int,int> > s;
    int b;
    cin>>b;
    int i=0;
    while (++i<pow(2,b))  {
        s.insert({bitset<32>(i).count(),i});
    }
    for (auto it:s) {
        cout <<it.second<<endl;
    }
}

Пояснення:

Створіть набір пар int, int. Перший int - це біт, другий - число. Пари порівнюють себе за своїм першим параметром, тому набір сортується за кількістю бітів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.