解释产生回文列表的递归函数

时间:2019-02-28 18:30:58

标签: python recursion

我最近遇到了以下功能。当试图解释它时,我最初迷失了试图理解如何将具有两个输入的第一个函数彼此相加,直到“ y”等于0或“ x”为止。此外,我发现奇怪的是,我不需要为“ x”或“ y”定义任何变量,只需在第二个函数中传递数字“ N”即可生成“回文”列表,例如[1, 6、15、20、15、6、1]在通过N = 7的情况下。有人可以帮助我理解第一个函数与其递归函数的关系,以及与第二个函数的关系如何产生数字列表?即这是什么样的算法?

def func(x, y):
  if y in (0, x):
    return 1
  return func(x-1, y-1) + func(x-1, y)



def func2(N):
  return [[func(x, y) for y in range(x + 1)] for x in range(N)][N-1]

3 个答案:

答案 0 :(得分:2)

正如@ user2357112所指出的,它与Pascal's triangle有关,而后者又与binomial expansions有关。 data() { return { dataresults: [], }; }, axios .get("api/getoutcome") .then((response) => { this.dataresults = response.data }) .catch(function(error) { console.warn(error); }); 返回的值是func2(N)的扩展系数。

例如,(x+y)^(N-1)使得(x+y)^2 = x^2 + 2xy + y^2返回func2(3)

另一个函数[1, 2, 1]只是递归地沿着Pascal的三角形移动,以确定该项的适当值。从链接中注意到,帕斯卡三角形中的每个项都是其正上方的两个项的总和。您的代码在底部的每个术语中都会遍历三角形一次,这使其效率比其他计算二项式展开系数的方法低得多。

您还可以直接计算二项式系数:

func(x,y)的系数由公式x^(n−k)*y^k给出,scipy.misc.comb提供了有效的实现方式

答案 1 :(得分:2)

我检测了您的内部功能,以细致入微地跟踪操作。每次递归都缩进2个空格;每个print都有一个标签,原始x, y值以及最近计算出的所有其他信息。

indent = ""
def func(x, y):
  global indent
  print(indent, "ENTER", x, y)
  indent += "  "    # increase output indentation

  if y in (0, x):
    result = 1
  else:
    part1 = func(x-1, y-1)
    print(indent, "PART1", x, y, part1)
    part2 = func(x-1, y)
    print(indent, "PART2", x, y, part2)

    result = part1 + part2

  indent = indent[2:]   # decrease output indentation
  print(indent, "LEAVE", x, y, result)
  return result


def func2(N):
  return [[func(x, y) for y in range(x + 1)] for x in range(N)][N-1]


print(func2(5))

输出:

 ENTER 0 0
 LEAVE 0 0 1
 ENTER 1 0
 LEAVE 1 0 1
 ENTER 1 1
 LEAVE 1 1 1
 ENTER 2 0
 LEAVE 2 0 1
 ENTER 2 1
   ENTER 1 0
   LEAVE 1 0 1
   PART1 2 1 1
   ENTER 1 1
   LEAVE 1 1 1
   PART2 2 1 1
 LEAVE 2 1 2
 ENTER 2 2
 LEAVE 2 2 1
 ENTER 3 0
 LEAVE 3 0 1
 ENTER 3 1
   ENTER 2 0
   LEAVE 2 0 1
   PART1 3 1 1
   ENTER 2 1
     ENTER 1 0
     LEAVE 1 0 1
     PART1 2 1 1
     ENTER 1 1
     LEAVE 1 1 1
     PART2 2 1 1
   LEAVE 2 1 2
   PART2 3 1 2
 LEAVE 3 1 3
 ENTER 3 2
   ENTER 2 1
     ENTER 1 0
     LEAVE 1 0 1
     PART1 2 1 1
     ENTER 1 1
     LEAVE 1 1 1
     PART2 2 1 1
   LEAVE 2 1 2
   PART1 3 2 2
   ENTER 2 2
   LEAVE 2 2 1
   PART2 3 2 1
 LEAVE 3 2 3
 ENTER 3 3
 LEAVE 3 3 1
 ENTER 4 0
 LEAVE 4 0 1
 ENTER 4 1
   ENTER 3 0
   LEAVE 3 0 1
   PART1 4 1 1
   ENTER 3 1
     ENTER 2 0
     LEAVE 2 0 1
     PART1 3 1 1
     ENTER 2 1
       ENTER 1 0
       LEAVE 1 0 1
       PART1 2 1 1
       ENTER 1 1
       LEAVE 1 1 1
       PART2 2 1 1
     LEAVE 2 1 2
     PART2 3 1 2
   LEAVE 3 1 3
   PART2 4 1 3
 LEAVE 4 1 4
 ENTER 4 2
   ENTER 3 1
     ENTER 2 0
     LEAVE 2 0 1
     PART1 3 1 1
     ENTER 2 1
       ENTER 1 0
       LEAVE 1 0 1
       PART1 2 1 1
       ENTER 1 1
       LEAVE 1 1 1
       PART2 2 1 1
     LEAVE 2 1 2
     PART2 3 1 2
   LEAVE 3 1 3
   PART1 4 2 3
   ENTER 3 2
     ENTER 2 1
       ENTER 1 0
       LEAVE 1 0 1
       PART1 2 1 1
       ENTER 1 1
       LEAVE 1 1 1
       PART2 2 1 1
     LEAVE 2 1 2
     PART1 3 2 2
     ENTER 2 2
     LEAVE 2 2 1
     PART2 3 2 1
   LEAVE 3 2 3
   PART2 4 2 3
 LEAVE 4 2 6
 ENTER 4 3
   ENTER 3 2
     ENTER 2 1
       ENTER 1 0
       LEAVE 1 0 1
       PART1 2 1 1
       ENTER 1 1
       LEAVE 1 1 1
       PART2 2 1 1
     LEAVE 2 1 2
     PART1 3 2 2
     ENTER 2 2
     LEAVE 2 2 1
     PART2 3 2 1
   LEAVE 3 2 3
   PART1 4 3 3
   ENTER 3 3
   LEAVE 3 3 1
   PART2 4 3 1
 LEAVE 4 3 4
 ENTER 4 4
 LEAVE 4 4 1
[1, 4, 6, 4, 1]

这对您来说足够多了吗?如果没有,您可以尝试将外部函数分解为一系列调用,以便可以在单独的操作中看到它们。

答案 2 :(得分:1)

了解Pascal三角形以及更有意义的函数和变量名称后,我相信您会发现代码易于说明。

这里是相同的代码,没有列表理解,但使用了更好的变量名:

# PASCAL'S TRIANGLE:
# line 1            1
# line 2          1   1
# line 3        1   2   1
# line 4      1   3   3   1
# line 5    1   4   6   4   1
#
# Each line has one more value thant the previous one
# Each position on a line is the sum of the two numbers above it
# those  are the ones at index i-1 an i respectively,
# except for edges that are always 1

def valueAt(line,position): # func(x,y)
    if position == 0 or position == line:
        return 1
    return valueAt(line-1,position-1) + valueAt(line-1,position)

def pascalLine(N): # func2(N)
    triangle = []
    for lineNumber in range(N):
        line = []
        for position in range(lineNumber+1):
            value = valueAt(lineNumber,position)
            line.append(value)
        triangle.append(line)
    return triangle[N-1]

顺便说一句,func2()效率很低,因为它会重新创建整个三角形以仅使用最后一行。或func()都是不必要的,因为func2()三角形中的每条新线都可以直接从上一行构建。

如果该想法是创建一个递归函数以基于上一行获得帕斯卡三角形的线,那么简单得多的事情就足够了:

def pLine(N):
    if N==1: return [1]
    line = pLine(N-1)
    return list(map(sum,zip([0]+line,line+[0])))