从0到2 ^ n-1(按POPCORN顺序)


18

...抱歉,这里没有爆米花,只有POPCNT。

编写最短的程序函数,该程序函数接受一个数字,n并以数字的二进制表示形式(popcount)以1位数字的升序输出从0到2 n -1的所有整数。不允许重复。

具有相同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 

输入和输出格式是实现定义的,以允许使用语言功能进一步修改代码。对输出有一些限制:

  • 数字必须以十进制格式输出。
  • 输出必须在数字之间包含合理的分隔符(允许使用尾随分隔符,但不能使用前导符)。

    换行(\n),标签(\t),空间,.;|-_/是相当合理的分隔符。我不介意额外的空格来进行漂亮的打印,但不要使用字母或数字作为分隔符。

  • 中的数字和隔板可以通过包围[ ]{ }或任何数组或列表符号。
  • 不要打印上面没有提到的其他内容。

奖金

如果您的解决方案可以即时生成数字,则将您的分数乘以0.5。这种好处的实质是,如果您要将打印解决方案直接转换为生成器,则生成器最多仅使用O(n)内存,其中n是如上定义的位数。(您不必实际将解决方案转换为生成器)。请注意,尽管我施加n <= 28,但存储所有数字所需的内存仍呈指数增长,并且一个幼稚的排序解决方案将在n = 28时占用至少4 GB的内存。

在申请此奖金之前,请添加一些关于您的解决方案工作原理的简单说明。


4
挑战似乎很无聊,并且会导致一堆排序问题。我想增加一些奖金,使挑战变得更加有趣。类似于“即时生成数字”的路线。如果您同意,请对此评论进行投票,然后将其添加到问题中。
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ 2015年

如果您不同意,请对此评论进行投票。
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ 2015年

在实时发布问题之前,请使用沙盒询问其他问题。
约翰·德沃夏克

21
@JanDvorak:它在沙盒上呆了一个月。
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

1
我认为这个问题为时已晚。通常,在我看来,您必须找出非平凡算法的问题不太适合进行代码高尔夫。让他们成为代码挑战,并提出您需要的所有约束。
FUZxxl 2015年

Answers:


10

Pyth,9个字节

osjN2U^2Q

o在的范围()内s,以2为底的表示形式(jN2)的总和。U2 ^ Q

Q= eval(input()))。

在这里尝试。


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

v通过此位旋转算法重复生成具有相同POPCOUNT 的下一个最高

实际上,事实证明,以减少的弹出次数生成它们,然后打印补语以使其增加,变得更容易。这样,然后v溢出2**n,我们只需除去where以外的所有n比特,就可以使最小的poppop数最小。这样,我们就可以做一个循环。可能有更好的解决方案,可以直接找到具有相同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̷̰̀ĥ̷̳ 2015年

1
我知道@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳,但我看不出如何以不同的方式保存字符。
xnor

使用幼稚的3循环方法,我在JS中的得分几乎相同(具有console.log()vs print)。也许技巧太重了。
edc65

节省一字节:v=N-~N
Sp3000

5

J,19个字符,无奖金。

[:(/:+/"1@#:)@i.2^]
  • 2 ^ y–二给力y
  • i. 2 ^ y–从0到的整数(2 ^ y) - 1
  • #: i. 2 ^ y –以整数2为底的每个整数。
  • +/"1 #: i. 2 ^ y –每个代表的总和
  • (i. 2 ^ y) /: +/"1 #: i. 2 ^ y–根据i. 2 ^ y前一个矢量项的顺序对矢量进行排序,这就是我们的答案。

3

Python,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

CJam,13个字节

2ri#,{2b1b}$p

非常简单的实现。

运作方式

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

在这里在线尝试


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,固定!谢谢!!!
Savenkov Alexey'3

1

JavaScript(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

Bash + coreutils,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̷̰̀ĥ̷̳ 2015年

我删除了该条款,因为人们似乎仍然没有注意到它。
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳现在,从理论上讲,它至少应该可以工作到28个。到目前为止,我已经测试了多达22个,但是当然这sort要花很长时间。当n = 28时,sort将需要对2 ^ 28行/〜13GB的数据进行排序。
Digital Trauma 2015年

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

用法示例:f 4,输出[0,1,2,4,8,3,5,9,6,10,12,7,11,13,14,15]

它是如何工作的:既不对[0..2 ^ n-1]进行排序也不对其进行重复迭代,也不寻找包含i 1s的数字。

#辅助函数有两个参数ab和构建了由每个数字的列表a1和b0。主函数f调用#进行的每个组合ab地方a+b平等n,没有1秒,启动n0有数字秩序。由于Haskell的懒惰,所有这些列表都不必在内存中完全构建。


++in的a#b意思不是意味着需要完全制作左侧(可能很大)然后复制,然后再生成结果中的第一项,从而违反了奖金要求?
Jules

嗯,不,考虑到它仍然可以在生产过程中懒惰地生成它们,只需要为每个项目制作一个副本,由于在处理过程中都可以将它们回收,这意味着空间使用是恒定的。不理我。
Jules

1

Ruby 47个字符

就像@KeithRandall的Python一样:

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

1

Mathematica,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

Perl,64/2 = 32

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

只需遍历范围[0..2^n-1] n + 1时间即可。在每次迭代中,仅打印1位数字等于迭代变量($i)的数字。通过对转换为二进制字符串的数字中1的(y/1//)进行计数来对位进行计数sprintf

测试

Perl,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̷̰̀ĥ̷̳ 2015年

2
我刚刚问过“怎么做”,因为我看不懂perl :)希望添加更多的解释吗?
Optimizer

@Optimizer,添加了更多说明。
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个字符:

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对。第一个int是位数,第二个是数字。线对根据其第一个参数进行比较,因此按位计数对集合进行排序。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.