Dari 0 hingga 2 ^ n - 1 dalam urutan POPCORN

18

... Ah maaf, tidak ada popcorn di sini, hanya POPCNT.

Tulis program atau fungsi terpendek yang mengambil angka ndan mengeluarkan semua bilangan bulat dari 0 hingga 2 n - 1, dengan urutan jumlah 1 bit dalam representasi biner angka (popcount). Duplikat tidak diizinkan.

Urutan angka dengan popcount yang sama ditentukan implementasi.

Misalnya, untuk n = 3, semua output ini valid:

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 input dan output ditentukan oleh implementasi untuk memungkinkan penggunaan fitur-fitur bahasa untuk menambah kode. Ada beberapa batasan pada output:

  • Angka-angka harus berupa output dalam format desimal.
  • Output harus mengandung pemisah yang masuk akal di antara angka-angka (trailing separator diperbolehkan, tetapi tidak mengarah).

    Line feed ( \n), tab ( \t), ruang, ,, ., ;, |, -, _, /yang separator cukup masuk akal. Saya tidak keberatan ruang tambahan untuk pencetakan cantik, tetapi jangan gunakan huruf atau angka sebagai pemisah.

  • Angka dan pemisah dapat dikelilingi oleh [ ], { }atau setiap array atau notasi daftar.
  • Jangan cetak apa pun yang tidak disebutkan di atas.

Bonus

Lipat gandakan skor Anda dengan 0,5 jika solusi Anda dapat menghasilkan angka dengan cepat. Inti dari bonus ini adalah jika Anda mengkonversi secara langsung solusi pencetakan Anda menjadi generator, generator hanya menggunakan paling banyak memori O (n) di mana n adalah jumlah bit seperti yang didefinisikan di atas. (Anda tidak harus benar-benar mengubah solusi Anda menjadi generator). Perhatikan bahwa sementara saya memaksakan n <= 28, memori yang diperlukan untuk menyimpan semua angka masih tumbuh secara eksponensial, dan solusi pengurutan yang naif akan memakan setidaknya 4 GB memori pada n = 28.

Harap tambahkan beberapa penjelasan sederhana tentang cara kerja solusi Anda sebelum mengklaim bonus ini.

n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
sumber
4
Tampaknya tantangan seperti itu cukup membosankan dan akan menghasilkan banyak jawaban pengurutan. Saya ingin menambahkan beberapa bonus untuk membuat tantangan lebih menarik. Sesuatu di sepanjang garis "menghasilkan angka dengan cepat". Jika Anda setuju dengan hal itu, harap berikan komentar ini, maka saya akan menambahkannya ke pertanyaan.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
Jika Anda tidak setuju, harap beri komentar pada komentar ini.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
Silakan gunakan kotak pasir untuk meminta saran lebih lanjut tentang pertanyaan sebelum mempostingnya secara langsung.
John Dvorak
21
@ JanDvorak: Sudah di sandbox selama satu bulan.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
1
Saya pikir sudah terlambat untuk pertanyaan ini. Secara umum, pertanyaan di mana Anda harus mencari algoritma non-sepele tidak cocok untuk golf kode menurut saya. Jadikan mereka sebagai tantangan kode dan ajukan semua kendala yang Anda butuhkan.
FUZxxl

Jawaban:

10

Pyth, 9 byte

osjN2U^2Q

order oleh sum dari representasi basis 2 ( jN2) pada rentang ( U) dari 2 ^ Q.

( Q= eval(input())).

Coba di sini.

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

Berulang-ulang menghasilkan tertinggi berikutnya vdengan POPCOUNT yang sama dengan algoritma bit- twiddling ini .

Sebenarnya, ternyata lebih mudah untuk menghasilkan mereka dalam mengurangi jumlah pop, kemudian mencetak komplemen untuk membuatnya meningkat. Dengan begitu, lalu vmeluap 2**n, kita cukup menghapus semua kecuali nbit dengan &Nmana N=2**n-1, dan itu memberi angka popcount terkecil satu lebih rendah. Dengan begitu, kita bisa melakukan satu loop. Mungkin ada solusi yang lebih baik yang secara langsung menemukan angka lebih rendah berikutnya dengan POPCOUNT yang sama.

Karena masalah fencepost, kita perlu memulainya v=2**(n+1)-1sehingga operasi menghasilkan v=N-1pada loop pertama.

Output untuk 4:

0
8
4
2
1
12
10
9
6
5
3
14
13
11
7
15
Tidak
sumber
Tidak perlu untuk meningkatkan jumlah popcount yang sama. Urutan ditentukan oleh implementasi.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
1
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Saya sadar, tetapi saya tidak melihat bagaimana cara menyimpan karakter dengan cara yang berbeda.
xnor
Dengan metode 3 loop naif, skor saya hampir sama di JS (memiliki console.log()vs print). Mungkin tipuannya terlalu berat.
edc65
Penghematan satu byte:v=N-~N
Sp3000
5

J, 19 karakter, tidak ada bonus.

[:(/:+/"1@#:)@i.2^]
  • 2 ^ y- Dua pangkat dari y.
  • i. 2 ^ y- bilangan bulat dari 0hingga (2 ^ y) - 1.
  • #: i. 2 ^ y - masing-masing bilangan bulat ini diwakili dalam basis dua.
  • +/"1 #: i. 2 ^ y - jumlah masing-masing representasi
  • (i. 2 ^ y) /: +/"1 #: i. 2 ^ y- vektor i. 2 ^ ydiurutkan berdasarkan urutan item dari vektor sebelumnya, jawaban kami.
FUZxxl
sumber
3

Python, 63 karakter

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
sumber
@Alex: Daftar pembatasan menyiratkan dia menginginkan hasil string.
Keith Randall
Maaf, ketinggalan itu.
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);}}}

atau sedikit lebih bagus diformat:

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

Apa itu?

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

menghitung angka terakhir untuk ditampilkan (pow (2, n) - 1)

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

loop luar mengulangi jumlah bit (jadi 0 hingga n-1) sedangkan loop dalam hanya dihitung dari 0 hingga m

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

Pada x86 ada instruksi POPCNT yang dapat digunakan untuk menghitung bit yang diset. GCC dan kompiler yang kompatibel dapat mendukung fungsi __builtin_popcount yang pada dasarnya mengkompilasi instruksi tersebut.

Felix Bytow
sumber
2

CJam, 13 byte

2ri#,{2b1b}$p

Implementasi yang cukup mudah.

Cara kerjanya :

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

Cobalah online di sini

Pengoptimal
sumber
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
sumber
@ MartinBüttner, Diperbaiki! Terima kasih!!!
Savenkov Alexey
1

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

Cara paling sederhana, bermain 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;
}

Tidak disatukan

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

Uji di Firefox / konsol FireBug

F(4)

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

edc65
sumber
1

Bash + coreutils, 66

Satu untuk Anda mulai:

jot -w2o%dpc $[2**$1] 0|dc|tr -d 0|nl -ba -v0 -w9|sort -k2|cut -f1
Trauma Digital
sumber
Tidak ada yang menarik di sini. Diberikan komentar Anda, saya dengan senang hati akan menghapus / merevisi jawaban ini jika Anda ingin mengubah pertanyaan.
Trauma Digital
Tidak yakin apakah saya harus menyorot program Anda harus bekerja untuk semua nilai n dari 0 hingga 28 inklusif. Saya tidak tahu berapa banyak jawaban di sini yang melewati persyaratan itu.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
Saya telah menghapus klausa, karena orang-orang sepertinya tidak menyadarinya.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Sekarang, secara teori setidaknya harus bekerja hingga 28. Saya telah menguji hingga 22 sejauh ini, tapi tentu saja ini sortmembutuhkan waktu lama. Dengan n = 28, sortperlu mengurutkan 2 ^ 28 baris / ~ 13GB data.
Trauma Digital
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)]

Contoh penggunaan:, f 4yang menghasilkan[0,1,2,4,8,3,5,9,6,10,12,7,11,13,14,15]

Cara kerjanya: tidak menyortir atau berulang kali mengulangi [0..2 ^ n-1] dan mencari angka yang mengandung i 1s.

Fungsi #helper mengambil dua parameter adan bdan membangun daftar setiap angka yang terdiri dari a1s dan b0s. Fungsi utama fpanggilan #untuk setiap kombinasi dari adan di bmana a+bsama n, dimulai dengan no 1s dan n0s untuk memiliki nomor-nomor secara berurutan. Berkat kemalasan Haskell, semua daftar itu tidak harus dibangun sepenuhnya dalam memori.

nimi
sumber
Bukankah ++in a#bberarti bahwa sisi kiri (yang bisa jadi besar) perlu diproduksi seluruhnya dan kemudian disalin sebelum item pertama dalam hasil diproduksi, sehingga melanggar persyaratan untuk bonus?
Jules
Ah, tidak, berpikir tentang hal itu masih bisa menghasilkan mereka sementara mereka sedang diproduksi, hanya perlu membuat salinan dari setiap item, yang karena keduanya dapat menjadi sampah yang dikumpulkan selama pemrosesan berarti bahwa penggunaan ruang konstan. Abaikan saya.
Jules
1

Ruby 47 chars

Mirip seperti Python dari @KeithRandall:

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

Mathematica, 26

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

Contoh:

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

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

alephalpha
sumber
0

Perl, 64/2 = 32

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

Lakukan iterate selama rentang [0..2^n-1] n + 1waktu. Di setiap iterasi, cetak hanya angka-angka yang memiliki jumlah 1 bit sama dengan variabel iterasi ( $i). Bit dihitung dengan menghitung 1's ( y/1//) dalam jumlah yang dikonversi ke string biner dengan sprintf.

Ujilah aku .

Perl, 63

Pendekatan penyortiran:

#!perl -l
print for sort{eval+(sprintf"%b-%b",$a,$b)=~y/0//dr}0..2**<>-1
nutki
sumber
1
@Optimizer, Ini menggunakan O (1) memori. Apa definisi lain yang kita miliki? Ups, itu tidak benar karena saya mencetaknya langsung :)
nutki
@Optimizer, diperbaiki.
nutki
Yah, saya menyadari hal ini ketika saya mengatur kondisi, tetapi saya tetap membiarkannya, karena saya ingin melihat apa jawaban yang berbelit-belit yang dapat dikemukakan orang.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
2
Saya hanya bertanya "bagaimana" karena saya tidak dapat membaca perl :) Ingin menambahkan lebih banyak penjelasan?
Pengoptimal
@ Opptizer, beberapa penjelasan ditambahkan.
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
sumber
0

C ++ 11, 117 karakter:

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

Tidak Disatukan:

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

Penjelasan:

Buat satu set int, int pasang. Int pertama adalah jumlah bit, yang kedua adalah angka. Pasangan membandingkan diri mereka sendiri berdasarkan parameter pertama mereka, sehingga himpunan diurutkan berdasarkan jumlah bit.

Nuklir
sumber