【问题标题】:Pascal's Triangle via Recursion通过递归的帕斯卡三角
【发布时间】:2017-04-28 19:45:42
【问题描述】:

谁能告诉我我当前的代码是否可行?我必须在不使用任何循环的情况下使用输入创建帕斯卡三角形。我一定会递归。

我在这上面花了 3 天时间,这是我能想到的最好的输出。

def pascal(curlvl,newlvl,tri):

  if curlvl == newlvl:
    return ""

  else:

    tri.append(tri[curlvl])

    print(tri)
    return pascal(curlvl+1,newlvl,tri)


def triLvl():
  msg = "Please enter the number of levels to generate:"

  triheight = int(input(msg))

  if triheight < 1:
    print("\n Sorry, the number MUST be positive\n Please try again.")
    return triLvl()

  else:
    return triheight



def main():

   triangle = [1]

   curlvl = 0

   print("Welcome to the Pascal's triangle generator.")

   usrTri = triLvl()
   print(triangle)
   pascal(curlvl,usrTri,triangle)



main()

【问题讨论】:

  • 为什么`triLvl()`也是递归的?
  • 乍一看,我没有看到增加了递归调用。 triangle[row][column] = triangle[row-1][column] + triangle[row-1][column+1] 处的条目(边界处除外,它始终为 1。
  • 欢迎来到 StackOverflow。请阅读并遵循帮助文档中的发布指南。 Minimal, complete, verifiable example 适用于此。在您发布 MCVE 代码并准确描述问题之前,我们无法有效地帮助您。我们应该能够将您发布的代码粘贴到文本文件中并重现问题。
  • 具体来说,你得到了什么输出,你期望什么,你在诊断问题时做了什么?

标签: python recursion pascals-triangle


【解决方案1】:

我们可以使用辅助函数pairs定义一个递归的pascal

pascal 将返回 [[Int]](一个 Int 数组数组)——例如,pascal(3) 将返回

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

好的,所以我会先向您展示所有代码,然后我会逐步解释某些部分

def pairs (xs):
  if 2 > len(xs):
    return []
  else:
    return [xs[0:2]] + pairs(xs[1:])

def pascal (n):
  def compute (prev):
    return [1] + [x + y for (x,y) in pairs(prev)] + [1]
  def aux (m, prev):
    if (m > n):
      return []
    else:
      return [prev] + aux(m + 1, compute(prev))
  return aux(1, [1])

[print(line) for line in pascal(5)]
# [1]
# [1, 1]
# [1, 2, 1]
# [1, 3, 3, 1]
# [1, 4, 6, 4, 1]

说明

我们真正关心的是pascal 函数——我们编写的其他所有内容都是根据我们编写pascal 的方式产生的,所以我先来回顾一下。

编写递归函数的一种非常常见的方法是使用内部辅助函数来跟踪我们计算的各种状态。我们将使用这种技术作为 pascal 函数的基础

def my_recursive_func (<parameters>):
  def aux (<state_parameters>):
    if (<base_condition>):
      return <base_value>
    else
      return aux(<updated_state>)
  return aux(<initial_state>)

我们已经知道如何为 pascal 函数填写一些样板文件

  • parameters 应该只是 n,一个整数,因为我们希望调用我们的函数,如 pascal(3)pascal(5) 等 - 不应接受其他参数
  • state_parameters——我们现在只知道两件事:1)我们需要一些值m,它的计数一直到n,每次递增1——和2)一些允许我们计算下一个的值排;我们称之为prev,因为每个帕斯卡行都是根据上一个
  • 计算的
  • base_condition – 当 m == n 我们知道我们已经生成了所有需要的行时,这就是我们想要停止递归的时候
  • base_value – 这是返回的最后一个值 – 还不太清楚应该是什么
  • updated_state - 我们将使用 m + 1 更新 m,并且我们将使用某种数组连接来更新行 - 在我们编写更多代码之前不确定
  • initial_state - 我们将在1 开始m,第一行pascal 是[1]

好的,让我们填写到目前为止的内容

def pascal (n):
  def aux (m, prev):
    if (m > n):
      return ?
    else:
      return aux(m + 1, ?)
  return aux(1, [1])

我们想做的是让pascal 构建我们的结果类似于这样

[[1]] + [[1, 1]] + [[1, 2, 1]] + [[1, 3, 3, 1]], ...]
# => [ [1], [1 ,1], [1, 2, 1], [1, 3, 3, 1], ... ]

所以为了写base_valueprev 的更新状态,我们需要考虑这个返回type。我们要返回[[Int]],这是一个列表,所以base_value可以简单地是空列表[]

这意味着在每一步中,我们实际上都希望将[prev] 和连接 (+) 连接到递归结果......

[prev] + aux(m + 1, <b>&lt;next_row&gt;</b>)

我们现在已经很接近了,让我们再次更新pascal,看看我们要完成什么

def pascal (n):
  def aux (m, prev):
    if (m > n):
      return []
    else:
      return [prev] + aux(m + 1, <next_row>)
  return aux(1, [1])

好的,那么难的部分来了——计算下一行,对吧?嗯,其实还不错。

# given
[1,2,1]

# the next row is
[1, (1 + 2), (2 + 1), 1]

或者另一个例子

# given
[1, 4, 6, 4, 1]

# the next row is
[1, (1 + 4), (4 + 6), (6 + 4), (4 + 1), 1]

所以模式是这样的:创建一个以1 开头的新数组,然后对于前一行中的每一对数字,将两个数字相加并将每个和附加到数组中,最后附加另一个 @ 987654368@。我们可以像使用这样的列表推导式在 python 中表达这一点

[1] + [x + y for (x,y) in pairs(prev)] + [1]

现在我们只需要弄清楚pairs 函数。 pairs 应该有如下合约

pairs([])        => []
pairs([a])       => []
pairs([a,b])     => [[a,b]]
pairs([a,b,c])   => [[a,b],[b,c]]
pairs([a,b,c,d]) => [[a,b],[b,c],[c,d]]

让我们现在实现它,并验证我们的实现是否符合合同。请注意,我在pascaloutside 中实现了这个函数,因为它是一个通用函数并且本身就很有用。为了计算帕斯卡行,我们需要添加成对的数字,但是添加或如何我们得到这些对或数字不应该留给pascal 函数本身的责任。

def pairs (xs):
  if 2 > len(xs):
    return []
  else:
    return [xs[0:2]] + pairs(xs[1:])

print(pairs([]))        # []
print(pairs([1]))       # []
print(pairs([1,2]))     # [[1,2]]
print(pairs([1,2,3]))   # [[1,2],[2,3]]
print(pairs([1,2,3,4])) # [[1,2],[2,3],[3,4]]

好的,这让我们现在非常接近。让我们再次更新pascal 函数,看看我们在哪里

def pascal (n):
  def aux (m, prev):
    if (m > n):
      return []
    else:
      return [prev] + aux(m + 1, [1] + [x + y for (x,y) in pairs(prev)] + [1])
  return aux(1, [1])

神圣的烟!我们已经完成了。 aux 调用下一行的内联计算看起来有点忙。让我们在pascal 中添加另一个名为compute 的助手来清理这些东西。现在我们完成了!

def pascal (n):
  def compute (prev):
    return [1] + [x + y for (x,y) in pairs(prev)] + [1]
  def aux (m, prev):
    if (m > n):
      return []
    else:
      return [prev] + aux(m + 1, compute(prev))
  return aux(1, [1])

彻底

如果你想显示那些愚蠢的文本和提示,你可以写main 类似下面的东西——这使所有 I/O 与我们的 pascalpairs 函数分开。这种关注点的分离和副作用的管理对于在程序的早期考虑很重要,因为很难重用功能超出我们的预期。

def main ():
  try:
    print("Pascal triangle generator")
    n = int(input("Pascal(x): x = "))
    if n < 1: raise
    [print(line) for line in pascal(n)]
  except:
    print("enter a non-zero positive integer")
    main()

# run program
main()

继续运行pascal(300) 或其他一些令人印象深刻的结果

【讨论】:

  • 哦 wups,我以为这是一个 JS 问题。让我快速翻译
【解决方案2】:

我不知道这是否是您正在寻找的,但它工作得很好:

from operator import add


def pascal(curlvl, newlvl, tri):
    if curlvl == newlvl:
        return ""
    elif curlvl == 0:
        tri.append(1)
        print (tri)
        return pascal(curlvl + 1, newlvl, tri)
    else:
        tmp = [1]
        rt = tri[:-1]
        rt.reverse()
        # print (map(add, rt, tri[:-1]))
        # In Python 3, map returns a generator.
        # Wrapping map in list makes this code compatible with
        # both Python 2 and 3
        tt = list(map(add, rt, tri[:-1]))
        if (len(tt) > 0):
            tmp.extend(tt)
        tmp.append(1)
        tri = tmp
        print (tri)
        return pascal(curlvl + 1, newlvl, tri)


def triLvl():
    msg = "Please enter the number of levels to generate:"

    triheight = int(input(msg))

    if triheight < 1:
        print("\n Sorry, the number MUST be positive\n Please try again.")
        return triLvl()

    else:
        return triheight


def main():
    triangle = [1]

    curlvl = 0

    print("Welcome to the Pascal's triangle generator.")

    usrTri = triLvl()
    print(triangle)
    pascal(curlvl, usrTri, triangle)


main()

【讨论】:

    【解决方案3】:

    递归帕斯卡三角形作为一个列表:

    P=lambda h:(lambda x:x+[[x+y for x,y in zip(x[-1]+[0],[0]+x[-1])]])(P(h-1))if h>1 else[[1]]
    print(P(10))
    

    我希望它可以帮助,我不知道'zip'和'map'是否被视为循环(它们肯定包含循环)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多