【问题标题】:Code-golf: generate pascal's triangleCode-golf:生成帕斯卡三角形
【发布时间】:2009-08-06 23:27:03
【问题描述】:

生成列表列表(或打印,我不介意)大小为 N 的 Pascal's Triangle,代码行数尽可能少!

这是我的尝试(python 2.6 中的 118 个字符,使用 a trick):

c,z,k=locals,[0],'_[1]'
p=lambda n:[len(c()[k])and map(sum,zip(z+c()[k][-1],c()[k][-1]+z))or[1]for _ in range(n)]

解释:

  • 列表解析的第一个元素(当长度为0时)是[1]
  • 接下来的元素通过以下方式获得:
  • 取出前一个列表并制作两个列表,一个在开头填充 0,另一个在末尾填充。
    • 例如对于第二步,我们采用 [1] 并制作 [0,1][1,0]
  • 将两个新列表逐个元素相加
    • 例如我们创建一个新列表 [(0,1),(1,0)] 并用 sum 映射。
  • 重复 n 次即可。

用法(带有漂亮的打印,实际上是代码-golf xD):

result = p(10)
lines = [" ".join(map(str, x)) for x in result]
for i in lines:
    print i.center(max(map(len, lines)))

输出:

             1             
            1 1            
           1 2 1           
          1 3 3 1          
         1 4 6 4 1         
       1 5 10 10 5 1       
      1 6 15 20 15 6 1     
    1 7 21 35 35 21 7 1    
   1 8 28 56 70 56 28 8 1  
1 9 36 84 126 126 84 36 9 1

【问题讨论】:

  • 如果关闭,我将投票重新开放。我喜欢代码高尔夫。我不明白这有什么不好。
  • 也许只有我一个人,但是......如果你不能用你的语言解析 XML 文件,我不会赞成。
  • @fortran,我对两者都很熟悉。我指的是代码高尔夫专门构建的专业语言,例如 K 和 J,在代码高尔夫问题中总是获得最多的投票,但除了代码高尔夫问题之外,你永远不会将它们用于任何其他事情。比 20 字符的 J 解决方案,比方说 50 个字符的 C 解决方案给我留下了深刻的印象。
  • @Triptych:K 和 J 不是代码高尔夫专用语言。另外,J 似乎有用于 xml 的模块,例如 jsoftware.com/jwiki/Addons/xml/sax
  • @Triptych:金融行业肯定在打代码,然后:kx.com/Customers/end-user-customers.php

标签: algorithm code-golf combinatorics discrete-mathematics pascals-triangle


【解决方案1】:

K (Wikipedia),15 个字符:

p:{x{+':x,0}\1}

示例输出:

  p 10
(1
 1 1
 1 2 1
 1 3 3 1
 1 4 6 4 1
 1 5 10 10 5 1
 1 6 15 20 15 6 1
 1 7 21 35 35 21 7 1
 1 8 28 56 70 56 28 8 1
 1 9 36 84 126 126 84 36 9 1
 1 10 45 120 210 252 210 120 45 10 1)

这也很容易解释:

p:{x {+':x,0} \ 1}
   ^ ^------^ ^ ^
   A    B     C D
  • p 是一个采用隐式参数x 的函数。

  • p 展开 (C) 匿名函数 (B) x 次 (A) 从 1 (D) 开始。

  • 1234563从(1 2 1)开始,它会产生(1 2 1 0),添加对(1 1+2 2+1 1+0),得到(1 3 3 1)

更新:适应了 K4,它又削掉了另外两个字符。作为参考,这里是原始的 K3 版本:

p:{x{+':0,x,0}\1}

【讨论】:

  • 太棒了!我强烈怀疑会比这更短。
【解决方案2】:

J,APL 家族中的另一种语言,9 个字符:

p=:!/~@i.

这使用了 J 的内置“组合”动词。

输出:

   p 10
1 1 1 1 1  1  1  1  1   1
0 1 2 3 4  5  6  7  8   9
0 0 1 3 6 10 15 21 28  36
0 0 0 1 4 10 20 35 56  84
0 0 0 0 1  5 15 35 70 126
0 0 0 0 0  1  6 21 56 126
0 0 0 0 0  0  1  7 28  84
0 0 0 0 0  0  0  1  8  36
0 0 0 0 0  0  0  0  1   9
0 0 0 0 0  0  0  0  0   1

【讨论】:

  • 我想知道摆脱 0 需要做多少工作。此外,您可能想要转置结果。
  • 转置很简单,只需在前面加上|:。在 J 中,您大部分时间都不想摆脱零,但如果您真的想要,这里有一种方法:p=:3 :'(1+i.y) ({.])&.> <"1|: !/~i.y'
  • 一种更短的方法来去除前导零并很好地打印出来:p=:":@(!~i.@>:)"0@i.
【解决方案3】:

Haskell,58 个字符:

r 0=[1]
r(n+1)=zipWith(+)(0:r n)$r n++[0]
p n=map r[0..n]

输出:

*Main> p 5
[[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1],[1,5,10,10,5,1]]

更具可读性:

-- # row 0 is just [1]
row 0     = [1]
-- # row (n+1) is calculated from the previous row
row (n+1) = zipWith (+) ([0] ++ row n) (row n ++ [0])
-- # use that for a list of the first n+1 rows
pascal n  = map row [0..n]

【讨论】:

  • 短:r n=take(n+1)$iterate(\a->zipWith(+)(0:a)$a++[0])[1]
【解决方案4】:

C 中的 69C:

f(int*t){int*l=t+*t,*p=t,r=*t,j=0;for(*t=1;l<t+r*r;j=*p++)*l++=j+*p;}

像这样使用它:

int main()
{
#define N 10
    int i, j;
    int t[N*N] = {N};

    f(t);

    for (i = 0; i < N; i++)
    {
        for (j = 0; j <= i; j++)
            printf("%d ", t[i*N + j]);
        putchar('\n');
    }
    return 0;
}

【讨论】:

  • 你在这里作弊! :p 函数只计算 1 行,你应该在你的字符数中包括在内存中生成的代码(或打印,以你来说更短/更容易)整个三角形
  • 嗯?不,它没有,该函数用整个三角形填充它传递的数组的左侧。
【解决方案5】:

F#: 81 个字符

let f=bigint.Factorial
let p x=[for n in 0I..x->[for k in 0I..n->f n/f k/f(n-k)]]

解释:我懒得像 Haskell 和 K 程序员那样聪明,所以我采取了直截了当的路线:帕斯卡三角形中的每个元素都可以使用第 n 行和第 k 行来唯一标识,其中的值每个元素都是n!/(k! (n-k)!

【讨论】:

    【解决方案6】:

    Python:75 个字符

    def G(n):R=[[1]];exec"R+=[map(sum,zip(R[-1]+[0],[0]+R[-1]))];"*~-n;return R
    

    【讨论】:

    • 很好地使用单个空格缩进来节省几个字符
    【解决方案7】:

    更短的序言版本(112 而不是 164):

    n([X],[X]).
    n([H,I|T],[A|B]):-n([I|T],B),A is H+I.
    p(0,[[1]]):-!.
    p(N,[R,S|T]):-O is N-1,p(O,[S|T]),n([0|S],R).
    

    【讨论】:

      【解决方案8】:

      另一个刺(python):

      def pascals_triangle(n):
          x=[[1]]
          for i in range(n-1):
              x.append(list(map(sum,zip([0]+x[-1],x[-1]+[0]))))
          return x
      

      【讨论】:

      • 来吧,代码高尔夫的目的是让它变得紧凑!所以将函数重命名为“p”并删除额外的缩进(1个空格就足够了)并添加字符数:p
      【解决方案9】:

      Haskell,164C 格式:

      i l=zipWith(+)(0:l)$l++[0]
      fp=map (concatMap$(' ':).show)f$iterate i[1]
      c n l=if(length l<n)then c n$' ':l++" "else l
      cl l=map(c(length$last l))l
      pt n=cl$take n fp
      

      不格式化,52C:

      i l=zipWith(+)(0:l)$l++[0]
      pt n=take n$iterate i[1]
      

      一种更易读的形式:

      iterateStep row = zipWith (+) (0:row) (row++[0])
      pascalsTriangle n = take n $ iterate iterateStep [1]
      
      -- For the formatted version, we reduce the number of rows at the final step:
      formatRow r = concatMap (\l -> ' ':(show l)) r
      formattedLines = map formatRow $ iterate iterateStep [1]
      centerTo width line =
          if length line < width
              then centerTo width (" " ++ line ++ " ")
              else line
      centerLines lines = map (centerTo (length $ last lines)) lines
      pascalsTriangle n = centerLines $ take n formattedLines
      

      和 perl,111C,没有居中:

      $n=<>;$p=' 1 ';for(1..$n){print"$p\n";$x=" ";while($p=~s/^(?= ?\d)(\d* ?)(\d* ?)/$2/){$x.=($1+$2)." ";}$p=$x;}
      

      【讨论】:

      • 需要{-# LANGUAGE ParallelListComp #-},IMO 应该计入您的角色总数...哎哟。
      • 或者命令行上的-fglasgow-exts...无论如何,都可以用zipWith编写,只用一个额外的字符
      • 在这种情况下,zipWith(+)(0:l)$l++[0] 会让你找回那个字符 :)
      【解决方案10】:

      方案 — 100 个字符的压缩版本

      (define(P h)(define(l i r)(if(> i h)'()(cons r(l(1+ i)(map +(cons 0 r)(append r '(0))) )))(l 1 '(1)))

      这是更易读的形式(269 个字符):

      (定义(帕斯卡高度) (定义(下一行) (地图+ (缺点 0 行) (追加行'(0)))) (定义(迭代 i 行) (如果(> i 高度) '() (缺点行 (iter (1+ i) (下一行))))) (iter 1 '(1)))

      【讨论】:

        【解决方案11】:

        VBA/VB6(392 个字符,带格式)

        Public Function PascalsTriangle(ByVal pRows As Integer)
        
        Dim iRow As Integer
        Dim iCol As Integer
        Dim lValue As Long
        Dim sLine As String
        
          For iRow = 1 To pRows
            sLine = ""
            For iCol = 1 To iRow
              If iCol = 1 Then
                lValue = 1
              Else
                lValue = lValue * (iRow - iCol + 1) / (iCol - 1)
              End If
              sLine = sLine & " " & lValue
            Next
            Debug.Print sLine
          Next
        
        End Function
        

        【讨论】:

          【解决方案12】:

          PHP 100 个字符

          $v[]=1;while($a<34){echo join(" ",$v)."\n";$a++;for($k=0;$k<=$a;$k++)$t[$k]=$v[$k-1]+$v[$k];$v=$t;}
          

          【讨论】:

            【解决方案13】:

            红宝石,83c:

            def p(n);n>0?(m=p(n-1);k=m.last;m+[([0]+k).zip(k+[0]).map{|x|x[0]+x[1]}]):[[1]];end
            

            测试:

            irb(main):001:0> def p(n);n>0?(m=p(n-1);k=m.last;m+[([0]+k).zip(k+[0]).map{|x|x[0]+x[1]}]):[[1]];end
            => nil
            irb(main):002:0> p(5)
            => [[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1]]
            irb(main):003:0> 
            

            【讨论】:

              【解决方案14】:

              另一种 python 解决方案,如果内置函数的名称更短,它可能会更短...106 个字符。

              from itertools import*
              r=range
              p=lambda n:[[len(list(combinations(r(i),j)))for j in r(i+1)]for i in r(n)]
              

              【讨论】:

                【解决方案15】:

                再试一次,在prolog中(我正在练习xD),不是太短,只有164c:

                s([],[],[]).
                s([H|T],[J|U],[K|V]):-s(T,U,V),K is H+J.
                l([1],0).
                l(P,N):-M is N-1,l(A,M),append(A,[0],B),s(B,[0|A],P).
                p([],-1).
                p([H|T],N):-M is N-1,l(H,N),p(T,M).
                

                解释:

                • s = 逐个元素求和
                • l = 三角形的第 N 行
                • p = 大小为 N 的整个三角形

                【讨论】:

                  【解决方案16】:

                  VBA,122 个字符:

                  Sub p(n)
                  For r = 1 To n
                  l = "1"
                  v = 1
                  For c = 1 To r - 1
                  v = v / c * (r - c)
                  l = l & " " & v
                  Next
                  Debug.Print l
                  Next
                  End Sub
                  

                  【讨论】:

                    【解决方案17】:

                    几年前我写了这个 C++ 版本:

                    #include <iostream>
                    int main(int,char**a){for(int b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0;b<atoi(a[1]);(d|f|h)>1?e*=d>1?--d:1,g*=f>1?--f:1,i*=h>1?--h:1:((std::cout<<(i*g?e/(i*g):1)<<" "?d=b+=c++==b?c=0,std::cout<<std::endl?1:0:0,h=d-(f=c):0),e=d,g=f,i=h));}
                    

                    【讨论】:

                      【解决方案18】:

                      以下只是一个返回List[List[Int]] 的Scala 函数。没有漂亮的印刷或任何东西。有什么改进建议吗? (我知道它效率低下,但这不是现在的主要挑战,是吗?)。 145 摄氏度。

                      def p(n: Int)={def h(n:Int):List[Int]=n match{case 1=>1::Nil;case _=>(0::h(n-1) zipAll(h(n-1),0,0)).map{n=>n._1+n._2}};(1 to n).toList.map(h(_))}
                      

                      或许:

                      def pascal(n: Int) = {
                        def helper(n: Int): List[Int] = n match {
                          case 1 => 1 :: List()
                          case _ => (0 :: helper(n-1) zipAll (helper(n-1),0,0)).map{ n => n._1 + n._2 }
                        }
                        (1 to n).toList.map(helper(_))
                      }
                      

                      (我是 Scala 菜鸟,所以请对我好一点:D)

                      【讨论】:

                        【解决方案19】:

                        Perl 版本(139 个字符,不含 shebang)

                        @p = (1,1);
                        while ($#p < 20) {
                            @q =();
                            $z = 0;
                            push @p, 0;
                            foreach (@p) {
                                push @q, $_+$z;
                                $z = $_
                            }
                            @p = @q;
                            print "@p\n";
                        }
                        

                        输出从 1 2 1 开始

                        【讨论】:

                        • (顺便说一句,您现在可以删除其他答案:p)
                        • 我会在我弄清楚如何做的时候。 (我是新来的,还在阅读常见问题解答)
                        【解决方案20】:

                        PHP,115 个字符

                        $t[][]=1;
                        for($i=1;$i<$n;++$i){
                        $t[$i][0]=1;
                        for($j=1;$j<$i;++$j)$t[$i][$j]=$t[$i-1][$j-1]+$t[$i-1][$j];
                        $t[$i][$i]=1;}
                        

                        如果您不关心 print_r() 是否以正确的顺序显示输出数组,您可以将其剃成 113 个字符,例如

                        $t[][]=1;
                        for($i=1;$i<$n;++$i){
                        $t[$i][0]=$t[$i][$i]=1;
                        for($j=1;$j<$i;++$j)$t[$i][$j]=$t[$i-1][$j-1]+$t[$i-1][$j];}
                        

                        【讨论】:

                          【解决方案21】:

                          Perl,63 个字符:

                          for(0..9){push@z,1;say"@z";@z=(1,map{$z[$_-1]+$z[$_]}(1..$#z))}
                          

                          【讨论】:

                            【解决方案22】:

                            我在 C++ (378c) 中的尝试。没有其他帖子那么好..但我为自己提出了自己的解决方案而感到自豪=)

                            int* pt(int n)
                            {
                              int s=n*(n+1)/2;
                              int* t=new int[s];
                            
                              for(int i=0;i<n;++i)
                                for(int j=0;j<=i;++j)
                                  t[i*n+j] = (!j || j==i) ? 1 : t[(i-1)*n+(j-1)] + t[(i-1)*n+j];
                              return t;
                            }
                            
                            int main()
                            {
                              int n,*t;
                              std::cin>>n;
                              t=pt(n);
                            
                              for(int i=0;i<n;++i)
                              {
                                for(int j=0;j<=i;j++)
                                  std::cout<<t[i*n+j]<<' ';
                                std::cout<<"\n";
                              }
                            }
                            

                            【讨论】:

                            • 代码高尔夫的目的是让短程序xD尝试至少删除多余的空格:-p
                            • 我删除了大部分空白并进行了其他小改动。
                            【解决方案23】:

                            老帖子,但我今天写这个是为了回应另一个论坛上的挑战:

                            def pascals_triangle(n):
                                x=[[1]]
                                for i in range(n-1):
                                    x.append([sum(i) for i in zip([0]+x[-1],x[-1]+[0])])
                                return x
                            
                            for x in pascals_triangle(5):
                                print('{0:^16}'.format(x))
                            
                                  [1]       
                                 [1, 1]     
                               [1, 2, 1]    
                              [1, 3, 3, 1]  
                            [1, 4, 6, 4, 1]
                            

                            【讨论】:

                            • 不要忘记添加字符数 ;-)
                            猜你喜欢
                            • 2012-10-24
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2018-10-04
                            • 2014-11-12
                            • 2015-01-29
                            • 2011-05-07
                            • 1970-01-01
                            相关资源
                            最近更新 更多