Von 0 bis 2 ^ n - 1 in der POPCORN-Reihenfolge

18

... Ah sorry, kein Popcorn hier, nur POPCNT.

Schreiben Sie das kürzeste Programm oder die kürzeste Funktion, die eine Zahl aufnimmt, nund geben Sie alle Ganzzahlen von 0 bis 2 n - 1 in aufsteigender Reihenfolge der Anzahl von 1 Bits in der binären Darstellung der Zahlen aus (Popcount) aus. Duplikate sind nicht erlaubt.

Die Reihenfolge der Nummern mit demselben Popcount ist implementierungsspezifisch.

Beispielsweise sind für n = 3alle diese Ausgaben gültig:

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

Das Eingabe- und Ausgabeformat ist implementierungsdefiniert, um die Verwendung von Sprachfeatures zu ermöglichen, um den Code weiter zu verbessern. Die Ausgabe unterliegt einigen Einschränkungen:

  • Die Zahlen müssen im Dezimalformat ausgegeben werden.
  • Die Ausgabe muss ein angemessenes Trennzeichen zwischen den Zahlen enthalten (nachstehendes Trennzeichen zulässig, jedoch nicht führend).

    Zeilenvorschub ( \n), Register ( \t), Raum, ,, ., ;, |, -, _, /ist durchaus sinnvoll Separator. Ich mag keine zusätzlichen Leerzeichen für hübsches Drucken, benutze aber keine Buchstaben oder Ziffern als Trennzeichen.

  • Die Zahlen und Separatoren können durch umgeben sein [ ], { }oder jede Anordnung oder Liste Notation.
  • Drucken Sie nichts anderes, als oben angegeben.

Bonus

Multiplizieren Sie Ihre Punktzahl mit 0,5 wenn Ihre Lösung die Zahl im Handumdrehen erzeugen kann. Der Sinn dieses Bonus ist, dass, wenn Sie Ihre Drucklösung direkt in einen Generator umwandeln, der Generator nur höchstens O (n) Speicher verwendet, wobei n die oben definierte Anzahl von Bits ist. (Sie müssen Ihre Lösung nicht unbedingt auf Generator umstellen). Beachten Sie, dass, während ich n <= 28 auferlege, der zum Speichern aller Zahlen benötigte Speicher immer noch exponentiell wächst und eine naive Sortierlösung mindestens 4 GB Speicher bei n = 28 belegen würde.

Bitte erläutern Sie kurz, wie Ihre Lösung funktioniert, bevor Sie diesen Bonus in Anspruch nehmen.

n̴̖̋h̴̖̋ã̷͉h̷̭̿d̷̰̀ĥ̷̳
quelle
4
Es scheint, dass die Herausforderung ziemlich langweilig ist und zu einer Reihe von Antworten führen würde. Ich möchte einen Bonus hinzufügen, um die Herausforderung interessanter zu gestalten. Etwas im Sinne von "Generieren der Zahlen im Handumdrehen". Wenn Sie damit einverstanden sind, stimmen Sie diesen Kommentar bitte hoch, dann werde ich ihn der Frage hinzufügen.
n̴̖̋h̷͉̃a̷̭̿h̷̭̿d̷̰̀ĥ̷̳
Wenn Sie nicht einverstanden sind, stimmen Sie diesem Kommentar zu.
n̴̖̋h̴̖̋a̷̭̿h̷̭̿d̸̡̅ẗ̵̨́
Verwenden Sie die Sandbox, um weitere Vorschläge zu einer Frage zu erhalten, bevor Sie sie live veröffentlichen.
John Dvorak
21
@ JanDvorak: Es war für einen Monat auf Sandkasten.
n̴̖̋h̷͉̃a̷̭̿h̷̭̿d̷̰̀ĥ̷̳
1
Ich denke, es ist zu spät für diese Frage. Generell sind Fragen, bei denen man einen nicht trivialen Algorithmus herausfinden muss, meiner Meinung nach nicht gut für Code-Golf geeignet. Machen Sie sie stattdessen zu einer Code-Herausforderung und stellen Sie alle Einschränkungen auf, die Sie benötigen.
FUZxxl

Antworten:

10

Pyth, 9 Bytes

osjN2U^2Q

oDurch die sum der Basis 2 liegende Darstellung ( jN2) über den Bereich ( U) von 2 ^ Q.

( Q= eval(input())).

Probieren Sie es hier aus.

isaacg
quelle
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

vMit diesem Bit-Twiddling-Algorithmus wird wiederholt der nächsthöhere Wert mit demselben POPCOUNT generiert .

Tatsächlich stellte sich heraus, dass es einfacher war, sie in abnehmender Popanzahl zu generieren und dann das Komplement auszudrucken, um es zu vergrößern. Auf diese Weise entfernen wir bei vÜberläufen 2**neinfach alle bis auf nBits mit &NwhereN=2**n-1 , und das ergibt die kleinste Popcount-Nummer, die um eins niedriger ist. Auf diese Weise können wir nur eine Schleife machen. Es gibt wahrscheinlich eine bessere Lösung, die mit demselben POPCOUNT direkt die nächstniedrigere Nummer findet.

Aufgrund eines Zaunpfostenproblems müssen wir mit beginnen v=2**(n+1)-1 , dass die Operation v=N-1in der ersten Schleife ausgeführt wird.

Ausgabe für 4:

0
8
4
2
1
12
10
9
6
5
3
14
13
11
7
15
xnor
quelle
Es ist nicht erforderlich, dass die Anzahl mit der gleichen Popcount erhöht wird. Die Reihenfolge ist implementierungsdefiniert.
n̴̖̋h̷͉̃a̷̭̿h̷̭̿d̷̰̀ĥ̷̳
1
@ n̴̖̋h̴̖̋ã̷͉h̷̭̿d̷̰̀ĥ̷̳ Mir ist bewusst, aber ich verstehe nicht, wie ich Charaktere anders speichern kann.
27.
Mit einer naiven 3-Schleifen-Methode erziele ich in JS (mit console.log()vs print) fast das gleiche Ergebnis . Vielleicht ist der Bittrick zu schwer.
edc65
Ein Byte sparen:v=N-~N
Sp3000
5

J, 19 Zeichen, kein Bonus.

[:(/:+/"1@#:)@i.2^]
  • 2 ^ y- Zwei hoch y.
  • i. 2 ^ y- die ganzen Zahlen von 0bis (2 ^ y) - 1.
  • #: i. 2 ^ y - jede dieser ganzen Zahlen in der Basis zwei dargestellt.
  • +/"1 #: i. 2 ^ y - die Beträge jeder Vertretung
  • (i. 2 ^ y) /: +/"1 #: i. 2 ^ y- der Vektor i. 2 ^ ysortiert nach der Reihenfolge der Elemente des vorherigen Vektors, unserer Antwort.
FUZxxl
quelle
3

Python, 63 Zeichen

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
quelle
@Alex: Die Liste der Einschränkungen implizierte, dass er ein String-Ergebnis haben wollte.
Keith Randall
Sorry, habe das verpasst.
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;}

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

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

oder etwas besser formatiert:

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

Was es macht?

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

berechnet die letzte anzuzeigende Zahl (pow (2, n) - 1)

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

Die äußere Schleife durchläuft die Anzahl der Bits (also 0 bis n-1), während die innere Schleife nur von 0 bis m zählt

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

Auf x86 gibt es den POPCNT-Befehl, mit dem die gesetzten Bits gezählt werden können. GCC und kompatible Compiler unterstützen möglicherweise die Funktion __builtin_popcount, die im Wesentlichen für diese Anweisung kompiliert wird.

Felix Bytow
quelle
2

CJam, 13 Bytes

2ri#,{2b1b}$p

Ziemlich einfache Implementierung.

Wie es funktioniert :

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

Probieren Sie es hier online aus

Optimierer
quelle
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
quelle
@ MartinBüttner, behoben! Vielen Dank!!!
Savenkov Alexey
1

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

Der einfachste Weg, Golf zu spielen

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

Ungolfed

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

Test In der Firefox / FireBug-Konsole

F(4)

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

edc65
quelle
1

Bash + Coreutils, 66

Eines, um Ihnen den Einstieg zu erleichtern:

jot -w2o%dpc $[2**$1] 0|dc|tr -d 0|nl -ba -v0 -w9|sort -k2|cut -f1
Digitales Trauma
quelle
Nichts wirklich aufregendes hier. In Anbetracht Ihres Kommentars werde ich diese Antwort gerne löschen / überarbeiten, wenn Sie die Frage ändern möchten.
Digital Trauma
Ich bin mir nicht sicher, ob ich Ihr Programm hervorheben soll, das für alle Werte von n von 0 bis einschließlich 28 funktionieren muss. Ich weiß nicht, wie viele Antworten hier diese Anforderung erfüllen.
n̴̖̋h̷͉̃a̷̭̿h̷̭̿d̷̰̀ĥ̷̳
Ich habe die Klausel entfernt, da die Leute es sowieso nicht zu bemerken scheinen.
n̴̖̋h̴̖̋a̷̭̿h̷̭̿d̷̰̀ĥ̷̳
@ n̴̖̋h̴̖̋ã̷͉h̷̭̿d̷̰̀ĥ̷̳ Nun, theoretisch sollte es mindestens bis 28 funktionieren. Ich habe bis jetzt bis zu 22 getestet, aber das dauert natürlich sortlange. Mit n = 28 sortmüssen 2 ^ 28 Zeilen / ~ 13 GB Daten sortiert werden.
Digital 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)]

Verwendungsbeispiel:, f 4welches ausgibt[0,1,2,4,8,3,5,9,6,10,12,7,11,13,14,15]

So funktioniert es: Weder sortieren noch wiederholt über [0..2 ^ n-1] iterieren und nach Zahlen suchen, die i 1s enthalten.

Die #Hilfsfunktionen akzeptieren zwei Parameter aund berstellen eine Liste aller Zahlen, die aus aEinsen und bNullen bestehen. Die Hauptfunktion fverlangt #nach jeder Kombination vona und bwo a+bgleich ist n, beginnend mit einer 1 und einer n0, um die Zahlen in der richtigen Reihenfolge zu haben. Dank Haskells Faulheit müssen all diese Listen nicht vollständig im Speicher erstellt werden.

nimi
quelle
Ist nicht die ++in a#bbedeutet , dass die linke Seite (die groß sein könnte) hergestellt werden muss vollständig und dann kopiert , bevor das erste Element in der Folge erzeugt wird, damit die Anforderungen für den Bonus zu verletzen?
Jules
Ah, nein, wenn Sie darüber nachdenken, können Sie sie während der Produktion immer noch träge erzeugen. Sie müssen lediglich eine Kopie von jedem Objekt erstellen, was bedeutet, dass die Speicherplatznutzung konstant ist, da beide während der Verarbeitung durch Müll gesammelt werden können. Ignoriere mich.
Jules
1

Ruby 47 Zeichen

Ähnlich wie beim Python von @KeithRandall:

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

Mathematica, 26

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

Beispiel:

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

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

Alephalpha
quelle
0

Perl, 64/2 = 32

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

Einfach [0..2^n-1] n + 1mal über den Bereich iterieren . In jeder Iteration werden nur die Zahlen ausgegeben, deren Anzahl von 1 Bit der Iterationsvariablen ( $i) entspricht. Bits werden durch Zählen von 1s ( y/1//) in der Zahl gezählt, die mit in eine Binärzeichenfolge umgewandelt wurde sprintf.

Teste mich .

Perl, 63

Sortieransatz:

#!perl -l
print for sort{eval+(sprintf"%b-%b",$a,$b)=~y/0//dr}0..2**<>-1
nutki
quelle
1
@Optimizer, Es verwendet O (1) Speicher. Welche andere Definition haben wir? Ups, das stimmt nicht, da ich es live
drucke
@Optimizer, behoben.
Nutki
Nun, ich bin mir dessen bewusst, als ich die Bedingung festlegte, aber ich erlaube es trotzdem, da ich sehen möchte, welche verschachtelten Antworten die Leute finden können.
n̴̖̋h̷͉̃a̷̭̿h̷̭̿d̷̰̀ĥ̷̳
2
Ich habe nur "wie" gefragt, da ich Perl nicht lesen kann :) Möchten Sie weitere Erklärungen hinzufügen?
Optimierer
@Optimizer, weitere Erklärung hinzugefügt.
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
quelle
0

C ++ 11, 117 Zeichen:

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

Ungolfed:

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

Erläuterung:

Erstellen Sie eine Reihe von int, int-Paaren. Das erste int ist die Anzahl der Bits, das zweite int ist die Anzahl. Paare vergleichen sich nach ihrem ersten Parameter, sodass die Menge nach der Anzahl der Bits sortiert wird.

Nuclear
quelle