POPCORN 순서로 0에서 2 ^ n-1 사이


18

... 아 죄송합니다. 팝콘은없고 POPCNT입니다.

최단 작성 프로그램 또는 기능 다수의 소요 n출력 2 모두 0의 정수 n은 1, 순서 오름차순 - 수의 이진 표현에서 1 비트의 수 (popcount 참조). 중복은 허용되지 않습니다.

동일한 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 

입력 및 출력 형식은 언어 기능을 사용하여 코드를 더욱 발전시킬 수 있도록 구현 정의되어 있습니다. 출력에는 몇 가지 제한 사항이 있습니다.

  • 숫자는 10 진수 형식으로 출력해야합니다.
  • 출력은 숫자 사이에 적절한 구분 기호를 포함해야합니다 (트레일 구분 기호는 허용되지만 앞쪽에는 허용되지 않음).

    라인 피드 ( \n), 탭 ( \t), 공간, ,, ., ;, |, -, _, /매우 합리적인 구분됩니다. 예쁜 인쇄를위한 추가 공간은 필요하지 않지만 문자 나 숫자를 구분 기호로 사용하지 마십시오.

  • 숫자와 세퍼레이터에 의해 포위 될 수있다 [ ], { }또는 배열이나리스트 표기법.
  • 위에 명시되지 않은 내용은 인쇄하지 마십시오.

보너스

솔루션에서 즉시 숫자를 생성 할 수 있으면 점수에 0.5를 곱하십시오 . 이 보너스의 핵심은 인쇄 솔루션을 생성기로 직접 변환하는 경우 생성기는 최대 O (n) 메모리 만 사용한다는 것입니다. 여기서 n은 위에 정의 된 비트 수입니다. 실제로 솔루션을 생성기로 변환 할 필요는 없습니다. n <= 28을 부과하는 동안 모든 숫자를 저장하는 데 필요한 메모리는 여전히 기하 급수적으로 증가하며 순진 정렬 솔루션은 n = 28에서 최소 4GB의 메모리를 차지합니다.

이 보너스를 청구하기 전에 솔루션 작동 방식에 대한 간단한 설명을 추가하십시오.


4
매우 지루하고 도전적인 답변이 많은 것처럼 보입니다. 도전을 더 재미있게하기 위해 보너스를 추가하고 싶습니다. "즉석에서 숫자를 생성하는"라인을 따라 뭔가. 당신이 그것에 대해 괜찮다면이 의견을 찬성하십시오. 그러면 질문에 추가 할 것입니다.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

동의하지 않으면이 의견을 찬성하십시오.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

샌드 박스를 사용하여 게시하기 전에 질문에 대한 추가 제안을 요청하십시오.
John Dvorak

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로 다음 최고 를 반복해서 생성합니다 .

실제로, 팝 카운트를 줄이면서 생성하는 것이 더 쉬운 것으로 나타났습니다. 그런 다음 보완을 인쇄하여 증가시킵니다. 그렇게하면 voverflows 2**n, where로 n비트를 제외한 모든 비트를 간단히 제거 하면 가장 적은 수의 popcount가 낮아집니다. 그렇게하면 루프를 하나만 수행 할 수 있습니다. 동일한 POPCOUNT로 다음으로 낮은 숫자 를 직접 찾는 더 나은 솔루션이있을 것입니다 .&NN=2**n-1

펜스 포스트 문제로 인해 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

같은 popcount를 가진 숫자를 증가시킬 필요가 없습니다. 순서는 구현 정의입니다.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

1
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ 나는 알고 있지만 문자를 다르게 저장하는 방법을 모르겠습니다.
xnor

순진한 3 루프 방법을 사용하면 JS에서 거의 동일한 점수를 얻습니다 ( console.log()vs print). 비트 트릭이 너무 무거울 수 있습니다.
edc65

1 바이트 절약 :v=N-~N
Sp3000

5

J, 19 자, 보너스 없음.

[:(/:+/"1@#:)@i.2^]
  • 2 ^ y– 2의 거듭 제곱 y.
  • i. 2 ^ y-에서 정수 0(2 ^ y) - 1.
  • #: i. 2 ^ y –이 정수 각각은 밑이 2로 표시됩니다.
  • +/"1 #: i. 2 ^ y – 각 표현의 합
  • (i. 2 ^ y) /: +/"1 #: i. 2 ^ yi. 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 : 제한 목록은 문자열 결과를 원한다는 것을 암시했습니다.
키이스 랜달

죄송합니다.
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;}

편집 : 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 함수를 지원할 수 있습니다.



2

매스 매 티카, 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, 고정! 감사!!!
Savenkov Alexey 2016 년

1

자바 스크립트 (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

배쉬 + 코어 유틸리티, 66

하나는 당신을 시작할 수 있습니다 :

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

여기서 흥미로운 것은 없습니다. 을 감안할 때 귀하의 코멘트 내가 행복하게 당신이 질문을 변경하려는 경우이 답변을 수정 / 삭제됩니다.
Digital Trauma

프로그램을 강조 표시 해야하는지 확실하지 않은 경우 0에서 28까지의 모든 n 값에 대해 작동해야합니다. 나는 여기에 얼마나 많은 답변이 그 요구 사항을 통과했는지 모르겠습니다.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

사람들은 어쨌든 눈치 채지 못하기 때문에 조항을 삭제했습니다.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ 이제 이론 상으로는 최대 28까지 작동해야합니다. 지금까지 최대 22 개까지 테스트했지만 sort시간이 오래 걸립니다. n = 28이면 sort2 ^ 28 줄 / ~ 13GB의 데이터를 정렬해야합니다.
Digital Trauma

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 1을 포함하는 숫자를 찾지 않습니다.

#헬퍼 함수는 두 개의 매개 변수를 사용 a하고 b그리고 만들어 모든 번호의 목록 구축 a1과 b0을. 주 함수 f는 1과 0으로 시작 하여 숫자가 순서대로되도록 #모든 where a및 equals 조합을 호출 합니다 . Haskell의 게으름 덕분에 모든 목록을 메모리에 완전히 구성 할 필요는 없습니다.ba+bnn


하지 않습니다 ++에서 a#b평균이 왼쪽 (대형이 될 수있는)이 전체 생산해야하고 그 결과의 첫 번째 항목이 때문에 보너스에 대한 요구 사항을 위반, 생산하기 전에 다음 복사 한?
Jules

아, 아니요, 생산되는 동안 여전히 게으르게 생성 할 수 있다고 생각하면 처리하는 동안 가비지 수집 될 수 있으므로 각 항목의 사본을 만들어야하기 때문에 공간 사용량이 일정합니다. 나를 무시하십시오.
Jules

1

루비 47 자

@KeithRandall의 Python과 매우 유사합니다.

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시간 동안 반복하십시오 . 각 반복에서 반복 변수 ( $i)와 동일한 1 비트 수를 갖는 숫자 만 인쇄하십시오 . 비트는을 사용 하여 이진 문자열로 변환 된 숫자에서 1's ( 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
방금 펄을 읽을 수 없어서 "어떻게"물었다.
Optimizer

@Optimizer, 추가 설명이 추가되었습니다.
nutki

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 쌍 세트를 작성하십시오. 첫 번째 정수는 비트 수이고 두 번째 정수는 숫자입니다. 쌍은 첫 번째 매개 변수에 따라 자체를 비교하므로 세트는 비트 수로 정렬됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.