Od 0 do 2 ^ n - 1 w kolejności POPCORN

18

... Ach, przepraszam, nie ma tu popcornu, tylko POPCNT.

Napisz najkrótszy program lub funkcję, która pobiera liczbę ni wypisuje wszystkie liczby całkowite od 0 do 2 n - 1, w porządku rosnącym liczby 1 bitów w binarnej reprezentacji liczb (popcount). Duplikaty nie są dozwolone.

Kolejność liczb z tym samym popcount jest zdefiniowana w implementacji.

Na przykład dla n = 3wszystkich tych danych wyjściowych są poprawne:

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

Format wejściowy i wyjściowy są zdefiniowane w implementacji, aby umożliwić korzystanie z funkcji językowych w celu dalszego kodowania kodu. Istnieje kilka ograniczeń dotyczących wyjścia:

  • Liczby muszą być wyprowadzane w formacie dziesiętnym.
  • Dane wyjściowe muszą zawierać rozsądny separator między liczbami (dozwolony separator końcowy, ale nie wiodący).

    Nowego wiersza ( \n), zakładka ( \t), przestrzeń, ,, ., ;, |, -, _, /są dość rozsądne separator. Nie mam nic przeciwko dodatkowym odstępom na ładne drukowanie, ale nie używam liter ani cyfr jako separatorów.

  • Liczby i separatory mogą być otoczone [ ], { }lub dowolnej macierzy lub listy notacji.
  • Nie drukuj niczego, co nie zostało wymienione powyżej.

Premia

Pomnóż swój wynik przez 0,5, jeśli Twoje rozwiązanie może wygenerować liczbę w locie. Duch tej premii polega na tym, że jeśli chcesz bezpośrednio przekonwertować swoje rozwiązanie drukowania na generator, generator używa tylko co najwyżej pamięci O (n), gdzie n jest liczbą bitów, jak zdefiniowano powyżej. (Nie musisz tak naprawdę przekształcać swojego rozwiązania w generator). Zauważ, że chociaż narzucam n <= 28, pamięć potrzebna do przechowywania wszystkich liczb wciąż rośnie wykładniczo, a naiwne rozwiązanie sortujące pochłonie co najmniej 4 GB pamięci przy n = 28.

Przed skorzystaniem z tej premii proszę dodać proste wyjaśnienie dotyczące działania rozwiązania.

n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨d̷̰̀ĥ̷̳
źródło
4
Wydaje się, że wyzwanie jest dość nudne i spowodowałoby wiele sortujących odpowiedzi. Chciałbym dodać trochę premii, aby wyzwanie było bardziej interesujące. Coś w stylu „generowania liczb w locie”. Jeśli się z tym zgadzasz, proszę zagłosować za tym komentarzem, a następnie dodam go do pytania.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨d̷̰̀ĥ̷̳
Jeśli się nie zgadzasz, proszę głosować za tym komentarzem.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨d̷̰̀ĥ̷̳
Użyj piaskownicy, aby poprosić o dalsze sugestie dotyczące pytania przed opublikowaniem go na żywo.
John Dvorak
21
@JanDvorak: To był na piaskownicy przez jeden miesiąc.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨d̷̰̀ĥ̷̳
1
Myślę, że na to pytanie jest za późno. Ogólnie rzecz biorąc, pytania, w których musisz wymyślić nietrywialny algorytm, nie są moim zdaniem odpowiednie dla golfa kodowego. Zrób z nich wyzwanie kodowe i stwórz wszystkie potrzebne ograniczenia.
FUZxxl

Odpowiedzi:

10

Pyth, 9 bajtów

osjN2U^2Q

ord przez sum reprezentacji podstawy 2 ( jN2) w przedziale ( U) z 2 ^ Q.

( Q= eval(input())).

Wypróbuj tutaj.

isaacg
źródło
7

Python 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

Wielokrotnie generuje następny najwyższy v z tym samym POPCOUNT przez ten algorytm kruszenia bitów .

W rzeczywistości łatwiej było wygenerować je w malejącej liczbie pop, a następnie wydrukować uzupełnienie, aby zwiększyć. W ten sposób, a następnie vprzelewa się 2**n, po prostu usuwamy wszystkie oprócz nbitów &NgdzieN=2**n-1 , a to daje najmniejszą liczbę popcount 1. W ten sposób możemy wykonać tylko jedną pętlę. Nie ma chyba lepsze rozwiązanie, które bezpośrednio znajdzie następną mniejszą liczbę o tej samej POPCOUNT.

Ze względu na problem z płotem musimy zacząć od v=2**(n+1)-1 tego, aby operacja zakończyła v=N-1się w pierwszej pętli.

Dane wyjściowe dla 4:

0
8
4
2
1
12
10
9
6
5
3
14
13
11
7
15
xnor
źródło
Nie ma potrzeby zwiększania liczby z tym samym popcount. Zamówienie jest zdefiniowane w implementacji.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨d̷̰̀ĥ̷̳
1
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨d̷̰̀ĥ̷̳ Wiem, ale nie widzę, jak zapisywać postacie robiące to inaczej.
xnor
Dzięki naiwnej metodzie 3 pętli uzyskuję prawie takie same wyniki w JS (mając console.log()vs print). Może ta sztuczka jest zbyt ciężka.
edc65
Oszczędność jednego bajtu:v=N-~N
Sp3000,
5

J, 19 znaków, bez premii.

[:(/:+/"1@#:)@i.2^]
  • 2 ^ y- dwa do potęgi y.
  • i. 2 ^ y- liczby całkowite od 0do (2 ^ y) - 1.
  • #: i. 2 ^ y - każda z tych liczb całkowitych reprezentowanych w podstawie drugiej.
  • +/"1 #: i. 2 ^ y - sumy każdej reprezentacji
  • (i. 2 ^ y) /: +/"1 #: i. 2 ^ y- wektor i. 2 ^ yposortowany według kolejności elementów poprzedniego wektora, nasza odpowiedź.
FUZxxl
źródło
3

Python, 63 znaki

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

>>> F(3)
'[0, 1, 2, 4, 3, 5, 6, 7]'
Keith Randall
źródło
@Alex: Lista ograniczeń sugeruje, że chciał wynik łańcucha.
Keith Randall
Przepraszam, przegapiłem to.
Alex A.
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;}

EDYCJA: 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);}}}

EDYCJA: 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);}}}

lub nieco ładniej sformatowany:

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);
        }
    }
}

Co to robi?

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

oblicza ostatnią liczbę do wyświetlenia (pow (2, n) - 1)

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

zewnętrzna pętla przechodzi przez liczbę bitów (czyli od 0 do n-1), podczas gdy wewnętrzna pętla liczy tylko od 0 do m

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

Na x86 znajduje się instrukcja POPCNT, za pomocą której można policzyć ustawione bity. GCC i kompatybilne kompilatory mogą obsługiwać funkcję __builtin_popcount, która zasadniczo kompiluje się z tą instrukcją.

Felix Bytów
źródło
2

CJam, 13 bajtów

2ri#,{2b1b}$p

Dość prosta implementacja.

Jak to działa :

2ri#,             "Get an array of 0 to 2^n - 1 integers, where n is the input";
     {    }$      "Sort by";
      2b1b        "Convert the number to binary, sum the digits";
            p     "Print the array";

Wypróbuj online tutaj

Optymalizator
źródło
2

Mathematica, 50 46

SortBy[Range[0,2^#-1],Tr@IntegerDigits[#,2]&]&

.

SortBy[Range[0,2^#-1],Tr@IntegerDigits[#,2]&]&

{0, 1, 2, 4, 8, 16, 3, 5, 6, 9, 10, 12, 17, 18, 20, 
24, 7, 11, 13, 14, 19, 21, 22, 25, 26, 28, 15, 
23, 27, 29, 30, 31}
Savenkov Alexey
źródło
@ MartinBüttner, naprawiono! Dzięki!!!
Savenkov Alexey
1

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

Najprostszy sposób, w golfa

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;
}

Bez golfa

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);
    }
  }
}

Przetestuj w konsoli Firefox / FireBug

F(4)

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

edc65
źródło
1

Bash + coreutils, 66

Jeden na początek:

jot -w2o%dpc $[2**$1] 0|dc|tr -d 0|nl -ba -v0 -w9|sort -k2|cut -f1
Cyfrowa trauma
źródło
Nic naprawdę ekscytującego tutaj. Biorąc pod uwagę twój komentarz , chętnie usunę / poprawię tę odpowiedź, jeśli chcesz zmienić pytanie.
Cyfrowa trauma
Nie jestem pewien, czy powinienem wyróżnić twój program musi działać dla wszystkich wartości n od 0 do 28 włącznie. Nie wiem, ile odpowiedzi tutaj spełnia ten wymóg.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨d̷̰̀ĥ̷̳
Usunąłem klauzulę, ponieważ ludzie i tak nie zauważają jej.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨dd
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨d̷̰̀ĥ̷̳ Teraz teoretycznie przynajmniej powinno działać do 28. Do tej pory testowałem do 22, ale oczywiście sortzajmuje to dużo czasu. Przy n = 28 sortkonieczne będzie sortowanie 2 ^ 28 linii / ~ 13 GB danych.
Cyfrowa trauma
1

Haskell, (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)]

Przykład użycia:, f 4który wyprowadza[0,1,2,4,8,3,5,9,6,10,12,7,11,13,14,15]

Jak to działa: ani sortowanie, ani wielokrotne iterowanie po [0..2 ^ n-1] i szukanie liczb zawierających i 1s.

Funkcje #pomocnicze przyjmują dwa parametry ai bkonstruują listę każdej liczby złożonej z a1 i b0. Główna funkcja fwywołuje #każdą kombinację ai bgdzie a+bjest równa n, zaczynając od nzer i zer, aby uporządkować liczby. Dzięki lenistwu Haskella wszystkie te listy nie muszą być budowane całkowicie w pamięci.

nimi
źródło
Czyż ++w a#boznaczałoby, że po lewej stronie (co może być duża) musi być wytwarzany w całości, a następnie skopiowane przed pierwsza pozycja w rezultacie jest produkowany, naruszając tym samym wymagania dotyczące premii?
Jules
Ach, nie, myślenie o tym może nadal leniwie generować je podczas ich produkcji, wystarczy wykonać kopię każdego elementu, który, ponieważ oba mogą być śmieciami zbierane podczas przetwarzania, oznacza, że ​​wykorzystanie miejsca jest stałe. Ignoruj ​​mnie.
Jules
1

Ruby 47 znaków

Podobnie jak Python z @KeithRandall:

f=->n{(0..1<<n).sort_by{|x|x.to_s(2).count ?1}}
steenslag
źródło
1

Mathematica, 26

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

Przykład:

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

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

alephalpha
źródło
0

Perl, 64/2 = 32

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

Po prostu powtarzaj [0..2^n-1] n + 1czasy zakresu . W każdej iteracji wypisuj tylko liczby, które mają liczbę 1 bitów równą zmiennej iteracyjnej ( $i). Bity są liczone przez zliczanie 1( y/1//) w liczbie zamienionej na ciąg binarny za pomocąsprintf .

Przetestuj mnie .

Perl, 63

Podejście do sortowania:

#!perl -l
print for sort{eval+(sprintf"%b-%b",$a,$b)=~y/0//dr}0..2**<>-1
nutki
źródło
1
@Optimizer, wykorzystuje pamięć O (1). Jaką mamy inną definicję? Ups, to nieprawda, bo
drukuję na
@Optimizer, naprawiony.
nutki
Cóż, zdaję sobie z tego sprawę, kiedy ustawiam warunek, ale i tak pozwalam, ponieważ chcę zobaczyć, jakie skomplikowane odpowiedzi mogą znaleźć ludzie.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨d̷̰̀ĥ̷̳
2
Właśnie zapytałem „jak”, bo nie potrafię czytać perla :) Chcesz dodać więcej wyjaśnień?
Optymalizator
@Optimizer, dodano więcej wyjaśnień.
nutki
0

Java 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);}}
cPu1
źródło
0

C ++ 11, 117 znaków:

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;}

Nie golfowany:

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;
    }
}

Wyjaśnienie:

Utwórz zestaw par int, int. Pierwsza int jest liczbą bitów, druga to liczba. Pary porównują się według pierwszego parametru, więc zestaw jest sortowany według liczby bitów.

Jądrowy
źródło