我有一个有两个递归调用的函数,我正在尝试将其转换为迭代函数。我已经弄明白我可以通过一个电话很容易地做到这一点,但我无法弄清楚如何合并另一个电话。
功能:
def specialMultiplication(n):
if n < 2:
return 1
return n * specialMultiplication(n-1) * specialMultiplication(n-2)
如果我只有其中一个,那将非常容易:
def specialMult(n, mult = 1):
while n > 1:
(n, mult) = (n-1, n * mult) # Or n-2 for the second one
return mult
我无法弄清楚如何添加第二个电话以获得正确的答案。谢谢!
答案 0 :(得分:6)
如果您不介意更改算法的结构,可以自下而上地计算值,从最小值开始。
<h1>
答案 1 :(得分:4)
使用辅助“待办事项列表”将递归转换为迭代函数:
def specialMultiplication(n):
to_process = []
result = 1
if n >= 2:
to_process.append(n)
while to_process: # while list is not empty
n = to_process.pop()
result *= n
if n >= 3:
to_process.append(n-1)
if n >= 4:
to_process.append(n-2)
return result
to_process
)n >= 2
,请将n
添加到列表to_process
不为空,但是从列表中弹出项目,乘以结果n-1 < 2
,请勿执行“左”操作(不要附加到工作清单)n-2 < 2
,请勿执行“正确”操作(不要附加到工作清单)此方法具有消耗较少堆栈的优点。我已经针对1到25之间的值对递归版本检查了结果,它们是相同的。
请注意,它仍然很慢,因为复杂度为O(2^n)
所以它从n=30
开始变得非常缓慢(当n增加1时,时间加倍)。我的笔记本电脑在12秒内计算出n=28
。
我在执行泛洪填充算法时成功使用此方法修复了堆栈溢出问题:Fatal Python error: Cannot recover from stack overflow. During Flood Fill但是这里的Blcknght答案更适合,因为它重新考虑了从一开始就计算它的方式。
答案 2 :(得分:2)
OP的函数具有与Fibonacci和Lucas函数相同的递归结构,只是f0,f1和g的值不同:
f(0) = f0
f(1) = f1
f(n) = g(f(n-2), f(n-1), n)
这是recurrence relation的示例。这是一般解决方案的迭代版本,以n步计算f(n)。它对应于自下而上的尾递归。
def f(n):
if not isinstance(n, int): # Can be loosened a bit
raise TypeError('Input must be an int') # Can be more informative
if n < 0:
raise ValueError('Input must be non-negative')
if n == 0:
return f0
i, fi_1, fi = 1, f0, f1 # invariant: fi_1, fi = f(i-1), f(i)
while i < n:
i += 1
fi_1, fi = fi, g(fi_1, fi, n) # restore invariant for new i
return fi
Blckknight的回答是这个
的简化版本