【问题标题】:Code Golf: Gray Code代码高尔夫:格雷代码
【发布时间】:2010-11-07 20:47:43
【问题描述】:

挑战

按字符数计算的最短程序,输出 n 位 Gray Coden 将是一个小于 1000100000(由于用户建议)的任意数字,该数字取自标准输入。格雷码将打印在标准输出中,如示例所示。

注意:我不希望程序在合理的时间内打印格雷码(n=100000 是矫枉过正);不过我确实希望它开始打印。

示例

输入

4

预期输出

0000
0001
0011
0010
0110
0111
0101
0100
1100
1101
1111
1110
1010
1011
1001
1000

【问题讨论】:

  • 鉴于 CW 在没有模组干预的情况下无法回答问题,现在是 [code-golf] 离开 Stack Overflow 的时候了。 Stack Exchange 提案Code Golf & Programming Puzzles 将是一个好地方,但它需要更多的承诺才能进入测试阶段......
  • 如果另一个论坛上线,希望现有的 CG 问题可以迁移。
  • @John,希望代表在迁移时会被计算在内:)
  • n=100000 似乎有点过分,不是吗?对于 4 位格雷码,有 16 个条目,每个条目 4 个字符长。这可以达到 64 个字节。外推原始的 1000 位格雷码将需要 1.02e298 兆字节。我认为这会破坏每个人的解决方案,只是递归的解决方案。
  • @Gabi:让 n 大于 32 或 64 有什么意义?这似乎是一个任意且不必要的要求?

标签: algorithm code-golf gray-code


【解决方案1】:

Python - 53 个字符

n=1<<input()
for x in range(n):print bin(n+x^x/2)[3:]

这个 54 字符的版本克服了 Python2 中范围的限制,所以 n=100000 可以工作!

x,n=0,1<<input()
while n>x:print bin(n+x^x/2)[3:];x+=1

69 个字符

G=lambda n:n and[x+y for x in'01'for y in G(n-1)[::1-2*int(x)]]or['']

75 个字符

G=lambda n:n and['0'+x for x in G(n-1)]+['1'+x for x in G(n-1)[::-1]]or['']

【讨论】:

  • 你不使用标准输入/输出
  • @Gabi,全新的迭代解决方案,使用标准输入/标准输出
【解决方案2】:

APL(29 个字符)

函数 F 为( 是“旋转”字符)

z←x F y
z←(0,¨y),1,¨⌽y

这会生成 5 位格雷码( 现在是 'rho' 字符)

F/5⍴⊂0,1

数字“5”可以更改,也可以是变量。

(对不可打印的 APL 字符感到抱歉。所以不会让我以新用户的身份发布图片)

【讨论】:

  • 使用键盘输入;将 '5' 替换为 ('Execute' 'QuoteQuad' )。这增加了 3 个字符:-/
【解决方案3】:

Impossible! 语言(54 个 58 字符)

#l{'0,'1}1[;@l<][%;~['1%+].>.%['0%+].>.+//%1+]<>%[^].>

试运行:

./impossible gray.i! 5
Impossible v0.1.28
00000
00001
00011
00010
00110
00111
00101
00100
01100
01101
01111
01110
01010
01011
01001
01000
11000
11001
11011
11010
11110
11111
11101
11100
10100
10101
10111
10110
10010
10011
10001
10000

(其实我不知道是否允许使用个人语言,因为不可能!仍在开发中,但我还是想发布它..)

【讨论】:

  • 只要不是专门为解决这个问题而创建的语言,就可以。
  • 当然这种语言不是为了解决这个问题而创建的 :) 它是一种通用的深奥语言或类似的东西..
  • 这实际上看起来像是一种漂亮的深奥语言(而且比某些语言更有用!)。提醒HP RPN代码的简洁形式:p但是当APL / J-golfers进入时......
  • 我仍在努力,但我怀疑我能否接近 APL 或 J.. 无论如何感谢您的赞美:)
  • @Jack 请提供下载编译器的链接,以便其他人可以测试您的解决方案
【解决方案4】:

Golfscript - 27 个字符

从标准输入读取,写入标准输出

~2\?:),{.2/^)+2base''*1>n}%

示例运行

$ echo 4 | ruby golfscript.rb gray.gs 
0000
0001
0011
0010
0110
0111
0101
0100
1100
1101
1111
1110
1010
1011
1001
1000

【讨论】:

    【解决方案5】:

    Ruby - 49 个字符

    (1<<n=gets.to_i).times{|x|puts"%.#{n}b"%(x^x/2)}
    

    这适用于 n=100000 没有问题

    【讨论】:

      【解决方案6】:

      C++,168 个字符,不包括空格:

      #include <iostream>
      #include <string>
      
      int r;
      
      void x(std::string p, char f=48)
      {
          if(!r--)std::cout<<p<<'\n';else
          {x(p+f);x(p+char(f^1),49);}
          r++;
      }
      int main() {
          std::cin>>r;
          x("");
          return 0;
      }
      

      【讨论】:

        【解决方案7】:

        Haskell,82 个字符:

        f a=map('0':)a++map('1':)(reverse a)
        main=interact$unlines.(iterate f[""]!!).read
        

        赢得胜利的无积分风格! (或至少少 4 次)。向 FUZxxl 致敬。

        上一个:86 个字符:

        f a=map('0':)a++map('1':)(reverse a)
        main=interact$ \s->unlines$iterate f[""]!!read s
        

        使用交互剪切两个笔画,一个使用 unlines。

        旧版:89 个字符:

        f a=map('0':)a++map('1':)(reverse a)
        main=readLn>>= \s->putStr$concat$iterate f["\n"]!!s
        

        请注意,懒惰会让您立即获得免费输出。

        【讨论】:

        • 这里可以使用interact吗?
        • 您还可以删除 unlines 并期望像 cat "123" | myprog 中的输入,这应该是合法的。
        • 它已经期望以这种方式输入。 unlines 用于将输出变成一个字符串进行交互。
        • ...节省的额外笔划是 (unlines + "") 比 (concat + "\n") 短一个
        • 这也是可能的:main=interact$unlines.(iterate f[""]!!).read。节省 4 个字符。
        【解决方案8】:

        Mathematica 50 个字符

        Nest[Join["0"<>#&/@#,"1"<>#&/@Reverse@#]&,{""},#]&
        

        感谢 A. Rex 的建议!

        以前的尝试

        这是我在 Mathematica 中的尝试(140 个字符)。我知道这不是最短的,但如果您熟悉函数式编程,我认为它是最容易遵循的(尽管这可能是我的语言偏见表现)。 addbit 函数采用 n 位格雷码并使用来自维基百科页面的逻辑返回一个 n+1 位格雷码。make gray code 函数以嵌套方式将 addbit 函数应用于 1 位格雷码,{{ 0}, {1}},直到创建 n 位版本。 charactercode 函数只打印 addbit 函数输出中不带大括号和逗号的数字。

        addbit[set_] := 
         Join[Map[Prepend[#, 0] &, set], Map[Prepend[#, 1] &, Reverse[set]]]
        MakeGray[n_] := 
         Map[FromCharacterCode, Nest[addbit, {{0}, {1}}, n - 1] + 48]
        

        【讨论】:

        • 我担心这看起来很像线路噪音,但这里有 85 个字符:p=Prepend;f=FromCharacterCode/@(Nest[Join[#~p~0&amp;/@#,#~p~1&amp;/@Reverse[#]]&amp;,{{}},#]+48)&amp;
        • 编辑后发布 91 个字符的解决方案,但 @A.雷克斯在之前的评论中发布了一个较短的。回滚,只留下更好的。
        • @belisarius:利用你的一些想法,可以变得更短。 j=Join;f=FromCharacterCode/@Nest[j[{48}~j~#&amp;/@#,{49}~j~#&amp;/@Reverse[#]]&amp;,{{}},#]&amp;
        • 短很多:f=Nest[Join["0"&lt;&gt;#&amp;/@#,"1"&lt;&gt;#&amp;/@Reverse@#]&amp;,{""},#]&amp;
        • @A. Rex Or for 50 char 删除 "f=" 并使用 %[n] 调用
        【解决方案9】:

        维基百科上Constructing an n-bit Gray code 中描述的简单 Python 实现:

        import sys
        
        def _gray(n):
          if n == 1:
            return [0, 1]
          else:
            p = _gray(n-1)
            pr = [x + (1<<(n-1)) for x in p[::-1]]
            return p + pr
        
        n = int(sys.argv[1])
        for i in [("0"*n + bin(a)[2:])[-n:] for a in _gray(n)]:
          print i
        

        (233 个字符)

        测试:

        $ python gray.py 4
        0000
        0001
        0011
        0010
        0110
        0111
        0101
        0100
        1100
        1101
        1111
        1110
        1010
        1011
        1001
        1000
        

        【讨论】:

          【解决方案10】:

          C,203 个字符

          这是一个牺牲品,用 C 语言:

          #include <stdio.h>
          #include <stdlib.h>
          
          int main(void)
          {
              char s[256];
              int b, i, j, m, g;
          
              gets(s);
              b = atoi(s);
          
              for (i = 0; i < 1 << b; ++i)
              {
                  g = i ^ (i / 2);
                  m = 1 << (b - 1);
          
                  for (j = 0; j < b; ++j)
                  {
                      s[j] = (g & m) ? '1' : '0';
                      m >>= 1;
                  }
                  s[j] = '\0';
                  puts(s);
              }
              return 0;
          }
          

          【讨论】:

          • 输入/输出为stdinstdout
          • 现已修复 - 使用标准输入进行输入
          【解决方案11】:

          C#,149143 个字符


          C# 不是代码高尔夫的最佳语言,但我想我还是会去。

          static void Main(){var s=1L<<int.Parse(Console.ReadLine());for(long i=0;i<s;i++){Console.WriteLine(Convert.ToString(s+i^i/2,2).Substring(1));}}
          

          可读版本:

          static void Main()
          {
              var s = 1L << int.Parse(Console.ReadLine());
              for (long i = 0; i < s; i++)
              {
                  Console.WriteLine(Convert.ToString(s + i ^ i / 2, 2).Substring(1));
              }
          }
          

          【讨论】:

          • 这不适用于 n > 64,不幸的是 C# 中没有变量类型可以容纳 1 64。
          • @BrokenGlass 你试过了吗?我投 1 的时间长是有原因的,它适用于 100000 对我来说很好。
          • 据我所知,当我尝试它时(这是有道理的),long 的值翻转并在某个值处变为负值 - 它会起作用,只是不是它应该的方式.
          • @BrokenGlass 该死,你是对的!我会继续调查。
          • 您的代码缩短为 135 个字符: static void Main(){long i=0,s=1
          【解决方案12】:

          这是我的 Fantom 祭品

          public static Str[]grayCode(Int i){if(i==1)return["0","1"];else{p:=grayCode(i-1);p.addAll(p.dup.reverse);p.each|s,c|{if(c<(p.size/2))p[c]="0"+s;else p[c]="1"+s;};return p}}
          

          (177 个字符)

          或扩展版:

           public static Str[] grayCode(Int i)  
           {      
             if (i==1) return ["0","1"]
             else{
               p := grayCode(i-1);
               p.addAll(p.dup.reverse);
               p.each |s,c| 
               { 
                 if(c<(p.size/2))   
                 {
                   p[c] = "0" + s
                 }
                 else
                 {
                   p[c] = "1" + s
                 }  
               }
              return p
              }
            }
          

          【讨论】:

            【解决方案13】:

            F#,152 个字符

            let m=List.map;;let rec g l=function|1->l|x->g((m((+)"0")l)@(l|>List.rev|>m((+)"1")))(x - 1);;stdin.ReadLine()|>int|>g["0";"1"]|>List.iter(printfn "%s")
            

            【讨论】:

            • 我无法抗拒把它打得更远一点(143 个字符):let m=List.map;;let rec g l=function|1->l|x->g(m(( +)"0")l@m((+)"1")(List.rev l))(x-1);;stdin.ReadLine()|>int|>g["0";"1" ]|>Seq.iter(printfn"%s")
            【解决方案14】:

            F# 180 175字符太多

            今天早上我做了另一个版本,简化了递归版本,但是由于递归,它不会做 100000。

            递归解决方案:

            let rec g m n l =
                if(m = n) then l
                else List.map ((+)"0") l  @ List.map ((+)"1") (List.rev(l)) |> g (m+1) n
            List.iter (fun x -> printfn "%s" x) (g 1 (int(stdin.ReadLine())) ["0";"1"]);;
            

            完成后,我为“100000”要求创建了一个工作版本 - 与此处显示的其他解决方案竞争太长了,我可能多次重新发明轮子,但与我拥有的许多解决方案不同在这里看到它可以使用非常非常多的位,嘿,对于 F# 菜鸟来说,这是一个很好的学习体验——我没有费心去缩短它,因为无论如何它太长了 ;-)

            迭代解决方案:(使用 100000+)

            let bits = stdin.ReadLine() |>int
            let n = 1I <<< bits
            
            let bitcount (n : bigint) =
                let mutable m = n
                let mutable c = 1
                while m > 1I do
                    m <- m >>>1
                    c<-c+1
                c
            
            let rec traverseBits m (number: bigint) =
                let highbit = bigint(1 <<< m)
                if m > bitcount number
                then number
                else
                    let lowbit = 1 <<< m-1
                    if (highbit&&& number) > 0I
                    then
                        let newnum = number ^^^ bigint(lowbit)
                        traverseBits (m+1) newnum
                    else traverseBits (m+1) number
            
            let res =  seq 
                        { 
                          for i in 0I..n do
                            yield traverseBits 1 i
                        }
            
            let binary n m = seq 
                              {
                                for i = m-1 downto 0 do
                                    let bit = bigint(1 <<< i)
                                    if bit &&&n > 0I
                                    then yield "1"
                                    else yield "0"
                              }
            
            Seq.iter (fun x -> printfn "%s"  (Seq.reduce (+) (binary x bits))) res
            

            【讨论】:

              【解决方案15】:

              Lua,156 个字符

              这是我在 Lua 中的尝试,尽我所能。

              LuaJIT(或带有 lua-bitop 的 lua):156 字节

              a=io.read()n,w,b=2^a,io.write,bit;for x=0,n-1 do t=b.bxor(n+x,b.rshift(x,1))for k=a-1,0,-1 do w(t%2^k==t%n and 0 or 1)t=t%2^k==t and t or t%2^k end w'\n'end
              

              Lua 5.2:154 字节

              a=io.read()n,w,b=2^a,io.write,bit32;for x=0,n-1 do t=b.XOR(n+x,b.SHR(x,1))for k=a-1,0,-1  do w(t%2^k==t%n and 0 or 1)t=t%2^k==t and t or t%2^k end w'\n'end
              

              【讨论】:

                【解决方案16】:

                在无剪辑的 Prolog 中(如果删除 '

                b(N,D):-D=0->nl;Q is D-1,H is N>>Q/\1,write(H),b(N,Q).
                
                c(N,D):-N=0;P is N xor(N//2),b(P,D),M is N-1,c(M,D).
                
                :-read(N),X is 1<< N-1,c(X,N).
                

                【讨论】:

                  【解决方案17】:

                  红宝石,50 个字符

                  (2**n=gets.to_i).times{|i|puts"%0#{n}d"%i.to_s(2)}
                  

                  【讨论】:

                    猜你喜欢
                    • 2010-12-17
                    • 1970-01-01
                    • 2010-12-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2010-11-28
                    • 2011-02-08
                    • 2010-10-24
                    相关资源
                    最近更新 更多