19

作为 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]

我怎样才能解决这个问题?

4

12 回答 12

25

好的代码审查:

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选择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退出,变慢变快...

于 2014-06-07T04:41:32.930 回答
12

我知道您想自己实现,但我解释的最佳方式是逐步完成实现。下面是我的做法,这个实现依赖于我对 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]
于 2014-06-07T04:08:47.457 回答
9

不使用 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,除此之外它会被分散。ref draw_beautiful for n>7)

对于 n < 7

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)

n = 100 的示例

于 2016-11-30T22:18:40.753 回答
2

这是我的尝试:

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()调用只生成下一行的中间
于 2014-06-07T04:18:58.177 回答
1

初学者 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])
于 2016-07-03T20:35:58.447 回答
1

这是一个优雅而高效的递归解决方案。我正在使用非常方便的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 毫秒。请注意,如果不增加默认递归深度限制,您将无法走得更高。

于 2017-09-14T05:31:54.323 回答
1
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)
于 2016-01-14T15:28:32.990 回答
1
# 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.
于 2015-11-27T08:05:38.890 回答
0
# 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
于 2016-01-19T18:59:59.957 回答
0

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

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() 函数接受迭代器(可以是零个或多个),创建一个迭代器,该迭代器根据传递的迭代器聚合项目,并返回元组的迭代器。

于 2019-10-18T10:53:11.693 回答
0

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

这是一个完整的代码示例

>>> 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.

于 2016-03-10T10:52:33.010 回答
0

当我和我的儿子一起制作介绍 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)

希望它有所帮助。

于 2021-02-04T04:50:20.567 回答