Da 0 a 2 ^ n - 1 in ordine POPCORN


18

... Ah scusa, niente popcorn qui, solo POPCNT.

Scrivi il programma o la funzione più breve che accetta un numero ne genera tutti gli interi da 0 a 2 n - 1, in ordine crescente di numero di 1 bit nella rappresentazione binaria dei numeri (popcount). Nessun duplicato consentito.

L'ordine dei numeri con lo stesso popcount è definito dall'implementazione.

Ad esempio, per n = 3, tutti questi output sono validi:

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

Il formato di input e output è definito dall'implementazione per consentire l'uso delle funzionalità del linguaggio per migliorare ulteriormente il codice. Ci sono alcune restrizioni sull'output:

  • I numeri devono essere emessi in formato decimale.
  • L'output deve contenere un separatore ragionevole tra i numeri (separatore finale consentito, ma non iniziale).

    Riga ( \n), scheda ( \t), lo spazio, ,, ., ;, |, -, _, /sono separatore abbastanza ragionevole. Non mi dispiace spazi aggiuntivi per la stampa carina, ma non uso lettere o cifre come separatori.

  • I numeri e i separatori possono essere racchiusi tra [ ], { }o qualsiasi array o notazione di elenco.
  • Non stampare nient'altro non indicato sopra.

indennità

Moltiplica il tuo punteggio per 0,5 se la tua soluzione può generare il numero al volo. Lo spirito di questo bonus è che se dovessi convertire direttamente la tua soluzione di stampa in un generatore, il generatore utilizza al massimo la memoria O (n) dove n è il numero di bit come definito sopra. (Non è necessario convertire effettivamente la soluzione in generatore). Si noti che mentre impongo n <= 28, la memoria necessaria per memorizzare tutti i numeri cresce ancora in modo esponenziale e una soluzione di ordinamento ingenuo ridurrebbe almeno 4 GB di memoria a n = 28.

Aggiungi una semplice spiegazione di come funziona la tua soluzione prima di richiedere questo bonus.


4
Sembra che la sfida sia piuttosto noiosa e si tradurrebbe in un sacco di risposte di smistamento. Vorrei aggiungere qualche bonus per rendere la sfida più interessante. Qualcosa sulla falsariga di "generare i numeri al volo". Se sei d'accordo, per favore vota questo commento, quindi lo aggiungerò alla domanda.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳,

Se non sei d'accordo, per favore vota questo commento.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳,

Si prega di utilizzare la sandbox per chiedere ulteriori suggerimenti su una domanda prima di pubblicarla dal vivo.
John Dvorak,

21
@JanDvorak: è stato sulla sandbox per un mese.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳,

1
Penso che sia troppo tardi per questa domanda. In generale, le domande in cui devi capire un algoritmo non banale non sono adatte al code golf secondo me. Rendili invece una sfida al codice e poni tutti i vincoli di cui hai bisogno.
FUZxxl,

Risposte:


10

Pyth, 9 byte

osjN2U^2Q

order dall'um sdella rappresentazione di base 2 ( jN2) nell'intervallo ( U) di 2 ^ Q.

( Q= eval(input())).

Provalo qui.


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

Genera ripetutamente il successivo più alto vcon lo stesso POPCOUNT di questo algoritmo bit-twiddling .

In realtà, è risultato più semplice generarli con un numero di pop decrescente, quindi stampare il complemento per aumentarlo. In questo modo, quindi vtrabocciamo 2**n, rimuoviamo semplicemente tutti i nbit tranne con &Nwhere N=2**n-1, e questo dà il numero più basso di popcount numero uno inferiore. In questo modo, possiamo fare solo un ciclo. Probabilmente esiste una soluzione migliore che trova direttamente il prossimo numero inferiore con lo stesso POPCOUNT.

A causa di un problema di fencepost, dobbiamo iniziare in v=2**(n+1)-1modo che l'operazione produca v=N-1sul primo loop.

Uscita per 4:

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

Non è necessario che il numero con lo stesso numero di pop sia in aumento. L'ordine è definito dall'implementazione.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳,

1
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Sono consapevole, ma non vedo come salvare i personaggi facendo diversamente.
xnor

Con un metodo ingenuo a 3 loop, segnerò quasi lo stesso in JS (avendo console.log()vs print). Forse il trucco è troppo pesante.
edc65,

Salvataggio di un byte:v=N-~N
Sp3000

5

J, 19 personaggi, nessun bonus.

[:(/:+/"1@#:)@i.2^]
  • 2 ^ y- due alla potenza di y.
  • i. 2 ^ y- i numeri interi da 0a (2 ^ y) - 1.
  • #: i. 2 ^ y - ciascuno di questi numeri interi rappresentati nella seconda base.
  • +/"1 #: i. 2 ^ y - le somme di ciascuna rappresentazione
  • (i. 2 ^ y) /: +/"1 #: i. 2 ^ y- il vettore i. 2 ^ yordinato in base all'ordine degli elementi del vettore precedente, la nostra risposta.

3

Python, 63 caratteri

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: l'elenco delle restrizioni implicava che voleva un risultato di stringa.
Keith Randall

Scusa, mi sono perso.
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;}

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

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

o un po 'più carino formattato:

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

Cosa fa?

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

calcola l'ultimo numero da mostrare (pow (2, n) - 1)

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

il loop esterno scorre il conteggio dei bit (quindi da 0 a n-1) mentre il loop interno conta da 0 a m

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

Su x86 è presente l'istruzione POPCNT che può essere utilizzata per contare i bit impostati. GCC e compilatori compatibili possono supportare la funzione __builtin_popcount che sostanzialmente viene compilata per tale istruzione.


2

CJam, 13 byte

2ri#,{2b1b}$p

Implementazione piuttosto semplice.

Come funziona :

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

Provalo online qui


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}

@ MartinBüttner, risolto! Grazie!!!
Savenkov Alexey,

1

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

Il modo più semplice, giocato a golf

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 nella console di Firefox / FireBug

F(4)

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


1

Bash + coreutils, 66

Uno per iniziare:

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

Niente di veramente eccitante qui. Dato il tuo commento, sarò felice di eliminare / rivedere questa risposta se vuoi cambiare la domanda.
Trauma digitale il

Non sono sicuro che dovrei evidenziare che il tuo programma deve funzionare per tutti i valori di n da 0 a 28 inclusi. Non so quante risposte qui soddisfino tale requisito.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

Ho rimosso la clausola, dal momento che le persone non sembrano notarlo comunque.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳,

@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Ora, almeno in teoria dovrebbe funzionare fino a 28. Finora ho provato fino a 22, ma ovviamente questo sortrichiede molto tempo. Con n = 28, sortsarà necessario ordinare 2 ^ 28 righe / ~ 13 GB di dati.
Trauma digitale

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)]

Esempio di utilizzo:, f 4quali output[0,1,2,4,8,3,5,9,6,10,12,7,11,13,14,15]

Come funziona: né ordinamento né ripetizione ripetuta su [0..2 ^ n-1] e ricerca di numeri contenenti i 1s.

Le #funzioni helper accettano due parametri ae bcostruiscono un elenco di ogni numero composto daa 1 e b0 secondi. La funzione principale frichiede #che ogni combinazione di ae bdove sia a+buguale n, iniziando con 1 e n0 senza avere i numeri in ordine. Grazie alla pigrizia di Haskell, tutte quelle liste non devono essere costruite completamente in memoria.


Non ritiene la ++in a#bmedia che il lato sinistro (che potrebbe essere di grandi dimensioni) deve essere interamente e poi copiato prima che il primo elemento nel risultato viene prodotto, violando così i requisiti per il bonus?
Jules,

Ah, no, pensarci può ancora generarli pigramente mentre vengono prodotti, deve solo fare una copia di ogni articolo, che poiché entrambi possono essere spazzati via durante l'elaborazione significa che l'utilizzo dello spazio è costante. Ignorarmi.
Jules,

1

Ruby 47 caratteri

Proprio come quello di Python di @KeithRandall:

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

1

Mathematica, 26

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

Esempio:

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

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


0

Perl, 64/2 = 32

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

Basta scorrere i [0..2^n-1] n + 1tempi di intervallo . In ogni iterazione stampa solo i numeri che hanno un numero di 1 bit uguale alla variabile di iterazione ( $i). I bit vengono contati contando 1's ( y/1//) nel numero convertito in stringa binaria con sprintf.

Metti alla prova me .

Perl, 63

Approccio di ordinamento:

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

1
@Optimizer, utilizza la memoria O (1). Quale altra definizione abbiamo? Oops, non è vero quando lo
stampo

@Optimizer, risolto.
Nutki,

Bene, ne sono consapevole quando imposto la condizione, ma lo permetto comunque, dal momento che voglio vedere quali risposte contorte possono venire le persone.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳,

2
Ho appena chiesto "come" non riesco a leggere perl :) Vuoi aggiungere altre spiegazioni?
Ottimizzatore,

@Optimizer, aggiunte altre spiegazioni.
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);}}

0

C ++ 11, 117 caratteri:

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

Spiegazione:

Crea un insieme di coppie int, int. Il primo int è il conteggio dei bit, il secondo è il numero. Le coppie si confrontano in base al loro primo parametro, quindi l'insieme viene ordinato in base al conteggio dei bit.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.