【问题标题】:Pascal's Triangle for PythonPython 的帕斯卡三角
【发布时间】:2014-06-07 03:35:53
【问题描述】:

作为 Python 的学习经验,我正在尝试编写自己版本的 Pascal 三角形。我花了几个小时(因为我刚刚开始),但我得出了这段代码:

pascals_triangle = []

def blank_list_gen(x):
    while len(pascals_triangle) < x:
        pascals_triangle.append([0])

def pascals_tri_gen(rows):
    blank_list_gen(rows)
    for element in range(rows):
        count = 1
        while count < rows - element:
            pascals_triangle[count + element].append(0)
            count += 1
    for row in pascals_triangle:
        row.insert(0, 1)
        row.append(1)
    pascals_triangle.insert(0, [1, 1])
    pascals_triangle.insert(0, [1])

pascals_tri_gen(6)

for row in pascals_triangle:
    print(row)

返回

[1]
[1, 1]
[1, 0, 1]
[1, 0, 0, 1]
[1, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 0, 0, 1]

但是,我不知道从这里去哪里。我已经把头撞在墙上好几个小时了。我想强调,我不希望你为我做这件事;只是把我推向正确的方向。作为一个列表,我的代码返回

[[1], [1, 1], [1, 0, 1], [1, 0, 0, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 1]]

谢谢。

编辑:我接受了一些很好的建议,我完全重写了我的代码,但我现在遇到了另一个问题。这是我的代码。

import math

pascals_tri_formula = []

def combination(n, r):
    return int((math.factorial(n)) / ((math.factorial(r)) * math.factorial(n - r)))

def for_test(x, y):
    for y in range(x):
        return combination(x, y)

def pascals_triangle(rows):
    count = 0
    while count <= rows:
        for element in range(count + 1):
            [pascals_tri_formula.append(combination(count, element))]
        count += 1

pascals_triangle(3)

print(pascals_tri_formula)

但是,我发现输出有点不受欢迎:

[1, 1, 1, 1, 2, 1, 1, 3, 3, 1]

我该如何解决这个问题?

【问题讨论】:

    标签: python pascals-triangle


    【解决方案1】:

    OK 代码审查:

    import math
    
    # pascals_tri_formula = [] # don't collect in a global variable.
    
    def combination(n, r): # correct calculation of combinations, n choose k
        return int((math.factorial(n)) / ((math.factorial(r)) * math.factorial(n - r)))
    
    def for_test(x, y): # don't see where this is being used...
        for y in range(x):
            return combination(x, y)
    
    def pascals_triangle(rows):
        result = [] # need something to collect our results in
        # count = 0 # avoidable! better to use a for loop, 
        # while count <= rows: # can avoid initializing and incrementing 
        for count in range(rows): # start at 0, up to but not including rows number.
            # this is really where you went wrong:
            row = [] # need a row element to collect the row in
            for element in range(count + 1): 
                # putting this in a list doesn't do anything.
                # [pascals_tri_formula.append(combination(count, element))]
                row.append(combination(count, element))
            result.append(row)
            # count += 1 # avoidable
        return result
    
    # now we can print a result:
    for row in pascals_triangle(3):
        print(row)
    

    打印:

    [1]
    [1, 1]
    [1, 2, 1]
    

    帕斯卡三角形的解释:

    这是"n choose k"的公式(即有多少种不同的方式(不考虑顺序),从n个项目的有序列表中,我们可以选择k个项目):

    from math import factorial
    
    def combination(n, k): 
        """n choose k, returns int"""
        return int((factorial(n)) / ((factorial(k)) * factorial(n - k)))
    

    一位评论者询问这是否与 itertools.combinations 有关 - 确实如此。 “n 选择 k” 可以通过从组合中获取元素列表的长度来计算:

    from itertools import combinations
    
    def pascals_triangle_cell(n, k):
        """n choose k, returns int"""
        result = len(list(combinations(range(n), k)))
        # our result is equal to that returned by the other combination calculation:
        assert result == combination(n, k)
        return result
    

    让我们看看这个演示:

    from pprint import pprint
    
    ptc = pascals_triangle_cell
    
    >>> pprint([[ptc(0, 0),], 
                [ptc(1, 0), ptc(1, 1)], 
                [ptc(2, 0), ptc(2, 1), ptc(2, 2)],
                [ptc(3, 0), ptc(3, 1), ptc(3, 2), ptc(3, 3)],
                [ptc(4, 0), ptc(4, 1), ptc(4, 2), ptc(4, 3), ptc(4, 4)]],
               width = 20)
    [[1],
     [1, 1],
     [1, 2, 1],
     [1, 3, 3, 1],
     [1, 4, 6, 4, 1]]
    

    我们可以避免重复使用嵌套列表理解:

    def pascals_triangle(rows):
        return [[ptc(row, k) for k in range(row + 1)] for row in range(rows)]
    
    >>> pprint(pascals_triangle(15))
    [[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],
     [1, 11, 55, 165, 330, 462, 462, 330, 165, 55, 11, 1],
     [1, 12, 66, 220, 495, 792, 924, 792, 495, 220, 66, 12, 1],
     [1, 13, 78, 286, 715, 1287, 1716, 1716, 1287, 715, 286, 78, 13, 1],
     [1, 14, 91, 364, 1001, 2002, 3003, 3432, 3003, 2002, 1001, 364, 91, 14, 1]]
    

    递归定义:

    我们可以使用三角形所示的关系递归地定义这个(效率较低,但在数学上可能更优雅的定义):

     def choose(n, k): # note no dependencies on any of the prior code
         if k in (0, n):
             return 1
         return choose(n-1, k-1) + choose(n-1, k)
    

    为了好玩,您可以看到每一行的执行时间越来越长,因为每行每次都必须从前一行重新计算几乎每个元素两次:

    for row in range(40):
        for k in range(row + 1):
            # flush is a Python 3 only argument, you can leave it out,
            # but it lets us see each element print as it finishes calculating
            print(choose(row, k), end=' ', flush=True) 
        print()
    
    
    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
    1 11 55 165 330 462 462 330 165 55 11 1
    1 12 66 220 495 792 924 792 495 220 66 12 1
    1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1
    1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1
    1 15 105 455 1365 3003 5005 6435 6435 5005 3003 1365 455 105 15 1
    1 16 120 560 1820 4368 8008 11440 12870 11440 8008 4368 1820 560 120 16 1
    1 17 136 680 2380 6188 12376 19448 24310 24310 19448 12376 6188 2380 680 136 17 1
    1 18 153 816 3060 8568 18564 31824 43758 48620 43758 31824 18564 8568 3060 816 ...
    

    看腻了Ctrl-C退出,变慢变快...

    【讨论】:

      【解决方案2】:

      我知道您想自己实现,但对我来说最好的解释方式是逐步完成实现。下面是我的做法,这个实现依赖于我对 Python 函数如何工作的相当完整的了解,所以你可能不想自己使用这段代码,但它可能会让你找到正确的方向。

      def pascals_triangle(n_rows):
          results = [] # a container to collect the rows
          for _ in range(n_rows): 
              row = [1] # a starter 1 in the row
              if results: # then we're in the second row or beyond
                  last_row = results[-1] # reference the previous row
                  # this is the complicated part, it relies on the fact that zip
                  # stops at the shortest iterable, so for the second row, we have
                  # nothing in this list comprension, but the third row sums 1 and 1
                  # and the fourth row sums in pairs. It's a sliding window.
                  row.extend([sum(pair) for pair in zip(last_row, last_row[1:])])
                  # finally append the final 1 to the outside
                  row.append(1)
              results.append(row) # add the row to the results.
          return results
      

      用法:

      >>> for i in pascals_triangle(6):
      ...     print(i)
      ... 
      [1]
      [1, 1]
      [1, 2, 1]
      [1, 3, 3, 1]
      [1, 4, 6, 4, 1]
      [1, 5, 10, 10, 5, 1]
      

      【讨论】:

        【解决方案3】:

        不使用 zip,但使用生成器:

        def gen(n,r=[]):
            for x in range(n):
                l = len(r)
                r = [1 if i == 0 or i == l else r[i-1]+r[i] for i in range(l+1)]
                yield r
        

        示例:

        print(list(gen(15)))
        

        输出:

        [[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], [1, 11, 55, 165, 330, 462, 462, 330, 165, 55, 11, 1], [1, 12, 66, 220, 495, 792, 924, 792, 495, 220, 66, 12, 1], [1, 13, 78, 286, 715, 1287, 1716, 1716, 1287, 715, 286, 78, 13, 1], [1, 14, 91, 364, 1001, 2002, 3003, 3432, 3003, 2002, 1001, 364, 91, 14, 1]]
        

        显示为三角形

        把它画成漂亮的三角形(仅适用于 n 7)

        对于 n

        def draw(n):
            for p in gen(n):
                print(' '.join(map(str,p)).center(n*2)+'\n')
        

        例如:

        draw(10)

        输出:

              1       
        
             1 1      
        
            1 2 1     
        
           1 3 3 1    
        
          1 4 6 4 1   
        
        1 5 10 10 5 1   
        

        适用于任何尺寸

        因为我们需要知道最大宽度,所以我们不能使用生成器

        def draw_beautiful(n):
            ps = list(gen(n))
            max = len(' '.join(map(str,ps[-1])))
            for p in ps:
                print(' '.join(map(str,p)).center(max)+'\n')
        

        示例(2): 适用于任何数字:

        draw_beautiful(100)
        

        【讨论】:

          【解决方案4】:

          这是我的尝试:

          def generate_pascal_triangle(rows):
              if rows == 1: return [[1]]
          
              triangle = [[1], [1, 1]] # pre-populate with the first two rows
          
              row = [1, 1] # Starts with the second row and calculate the next
          
              for i in range(2, rows):
                  row = [1] + [sum(column) for column in zip(row[1:], row)] + [1]
                  triangle.append(row)
          
              return triangle
          
          for row in generate_pascal_triangle(6):
              print row
          

          讨论

          • 三角形的前两行是硬编码的
          • zip() 调用基本上将两个相邻的数字配对在一起
          • 我们仍然需要在开头添加 1,在末尾添加 1,因为 zip() 调用只会生成下一行的中间部分

          【讨论】:

            【解决方案5】:
            # combining the insights from Aaron Hall and Hai Vu,
            # we get:
            
            def pastri(n):
                rows = [[1]]
                for _ in range(1, n+1):
                    rows.append([1] +
                                [sum(pair) for pair in zip(rows[-1], rows[-1][1:])] +
                                [1])
                return rows
            
            # thanks! learnt that "shape shifting" data,
            # can yield/generate elegant solutions.
            

            【讨论】:

              【解决方案6】:
              def pascal(n):
                  if n==0:
                      return [1]
                  else:
                      N = pascal(n-1)
                      return [1] + [N[i] + N[i+1] for i in range(n-1)] + [1]
              
              
              def pascal_triangle(n):
                  for i in range(n):
                      print pascal(i)
              

              【讨论】:

                【解决方案7】:

                这里是 Python 初学者。这是我的尝试,一种非常直接的方法,使用两个 For 循环:

                pascal = [[1]]
                num = int(input("Number of iterations: "))
                print(pascal[0]) # the very first row
                for i in range(1,num+1):
                    pascal.append([1]) # start off with 1
                    for j in range(len(pascal[i-1])-1):
                    # the number of times we need to run this loop is (# of elements in the row above)-1
                        pascal[i].append(pascal[i-1][j]+pascal[i-1][j+1])
                        # add two adjacent numbers of the row above together
                    pascal[i].append(1) # and cap it with 1
                    print(pascal[i])
                

                【讨论】:

                  【解决方案8】:

                  这是一个优雅高效的递归解决方案。我正在使用非常方便的toolz 库。

                  from toolz import memoize, sliding_window
                  
                  @memoize
                  def pascals_triangle(n):
                      """Returns the n'th row of Pascal's triangle."""
                      if n == 0:
                          return [1]
                      prev_row = pascals_triangle(n-1)
                      return [1, *map(sum, sliding_window(2, prev_row)), 1]
                  

                  pascals_triangle(300) 在 macbook pro(2.9 GHz Intel Core i5)上大约需要 15 毫秒。请注意,在不增加默认递归深度限制的情况下,您不能走得更高。

                  【讨论】:

                  • 速度惊人!
                  【解决方案9】:

                  我从流行的fibonacci sequence 解决方案中作弊。对我来说,帕斯卡三角形的实现将具有与斐波那契相同的概念。在斐波那契中,我们一次使用一个数字并将其与前一个数字相加。在帕斯卡三角形中,一次使用一行并将其与前一行相加。

                  这是一个完整的代码示例

                  >>> def pascal(n):
                  ...     r1, r2 = [1], [1, 1]
                  ...     degree = 1
                  ...     while degree <= n:
                  ...         print(r1)
                  ...         r1, r2 = r2, [1] + [sum(pair) for pair in zip(r2, r2[1:]) ] + [1]
                  ...         degree += 1
                  

                  测试

                  >>> pascal(3)
                  [1]
                  [1, 1]
                  [1, 2, 1]
                  >>> pascal(4)
                  [1]
                  [1, 1]
                  [1, 2, 1]
                  [1, 3, 3, 1]
                  >>> pascal(6)
                  [1]
                  [1, 1]
                  [1, 2, 1]
                  [1, 3, 3, 1]
                  [1, 4, 6, 4, 1]
                  [1, 5, 10, 10, 5, 1]
                  

                  注意:要将结果作为生成器,请将 print(r1) 更改为 yield r1

                  【讨论】:

                    【解决方案10】:
                    # call the function ! Indent properly , everything should be inside the function
                    def triangle():
                    
                              matrix=[[0 for i in range(0,20)]for e in range(0,10)]         # This method assigns 0's to all Rows and Columns , the range is mentioned
                              div=20/2           # it give us the most middle columns 
                              matrix[0][div]=1        # assigning 1 to the middle of first row 
                              for i in range(1,len(matrix)-1): # it goes column by column
                                   for j in range(1,20-1):  #  this loop goes row by row
                                       matrix[i][j]=matrix[i-1][j-1]+matrix[i-1][j+1]               # this is the formula , first element of the matrix gets , addition of i index (which is 0 at first ) with third value on the the related row
                        # replacing 0s with spaces :) 
                              for i in range(0,len(matrix)):
                                  for j in range(0,20):
                                       if matrix[i][j]==0:       #  Replacing 0's with spaces
                                            matrix[i][j]=" "
                    
                              for i in range(0,len(matrix)-1):           # using spaces , the triangle will printed beautifully 
                                    for j in range(0,20):
                                        print 1*" ",matrix[i][j],1*" ", # giving some spaces in two sides of the printing numbers
                    triangle() # calling the function
                    

                    会打印这样的东西

                                           1
                                    1              1
                               1           2            1
                          1         3            3            1
                      1        4        6            4               1
                    

                    【讨论】:

                    • 我在每一行旁边写了 cmets,它解释了一切。您应该知道有两个功能,1-询问列数和行数,列应输入双倍行数。 2-正在打印帕斯卡三角形,主要逻辑或公式是 matrix[i][j]=matrix[i-1][j-1]+matrix[i-1][j+1] .... 你需要有 1 个为空的二维数组。
                    【解决方案11】:

                    这是实现帕斯卡三角形的简单方法:

                    def pascal_triangle(n):
                        myList = []
                        trow = [1]
                        y = [0]
                        for x in range(max(n,0)):
                            myList.append(trow)
                            trow=[l+r for l,r in zip(trow+y, y+trow)]
                    
                        for item in myList:
                            print(item)
                    
                    pascal_triangle(5)
                    

                    Python zip() 函数返回 zip 对象,它是元组的迭代器,其中每个传递的迭代器中的第一项配对在一起,然后每个传递的迭代器中的第二项配对在一起。 Python zip 是在其中保存真实数据的容器。

                    Python zip() 函数接受迭代器(可以是零个或多个),创建一个迭代器,根据传递的迭代器聚合项目,并返回元组的迭代器。

                    【讨论】:

                      【解决方案12】:

                      当我和我儿子一起制作介绍 python 时,我这样做了。当我们瞄准时,它开始时相当简单 -

                      1
                      1 2
                      1 2 3
                      1 2 3 4 
                      

                      但是,一旦我们使用实际算法,复杂性就超出了我们的预期。无论如何,我们确实构建了这个 -

                                   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
                      

                      使用了一些递归 -

                      def genRow(row:list) :  
                        # print(f"generatig new row below {row}")
                        # printRow(row)
                        l = len(row) #2
                        newRow : list = []
                        i = 0
                        # go through the incoming list
                        while i <= l:
                          # print(f"working with i = {i}")
                          # append an element in the new list
                          newRow.append(1)
                          # set first element of the new row to 1
                          if i ==0:
                            newRow[i] = 1
                            # print(f"1:: newRow = {newRow}")
                      
                          # if the element is in the middle somewhere, add the surroundng two elements in
                          # previous row to get the new element
                          # e.g. row 3[2] = row2[1] + row2[2]
                          elif i <= l-1:
                            # print(f"2:: newRow = {newRow}")      
                            newRow[i] = row[i-1] + row[i]
                          else:
                            # print(f"3 :: newRow = {newRow}")      
                            newRow[i] = 1
                          
                          i+=1
                        # print(newRow)
                        return newRow
                      
                      def printRow(mx : int, row:list):
                        n = len(row)
                        spaces = ' ' *((mx - n)*2)
                        print(spaces,end=' ')
                        for i in row:
                          print(str(i) + '  ',end = ' ')
                        print(' ')
                      
                      
                      r = [1,1]
                      mx = 7
                      printRow(mx,[1])
                      printRow(mx,r)
                      
                      for a in range(1,mx-1):
                        # print(f"working for Row = {a}")
                        if len(r) <= 2:
                          a1 = genRow(r)
                          r=a1
                        else:
                          a2 = genRow(a1)
                          a1 = a2
                        printRow(mx,a1)
                      

                      希望对您有所帮助。

                      【讨论】:

                        猜你喜欢
                        • 2012-10-24
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2021-12-28
                        • 2012-07-13
                        • 1970-01-01
                        相关资源
                        最近更新 更多