我编写了以下两个用于计算Fibonacci序列元素的代码。
def fib(n):
zero, one = 0, 1
k = 1
while k < n:
zero, one = one, zero + one
k = k + 1
return one, ls
def fib2(n, memo=None):
if memo is None:
memo = {}
if n == 1 or n == 2:
return 1
if n in memo:
return memo[n]
else:
memo[n-1] = fib2(n-1, memo)
memo[n-2] = fib2(n-2, memo)
return memo[n-1] + memo[n-2]
##import timeit
##
##print('Fibonacci 1:', timeit.timeit('fib(10000)', '''def fib(n):
## zero, one = 0, 1
## k = 1
## while k < n:
## zero, one = one, zero + one
## k = k + 1
## return one''', number=100))
##
##print('Fibonacci 2:', timeit.timeit('fib2(10000)', '''import sys; sys.setrecursionlimit(10001);
##def fib2(n, memo=None):
## if memo is None:
## memo = {}
## if n == 0 or n == 1:
## return 1
## if n in memo:
## return memo[n]
## else:
## memo[n-1] = fib2(n-1, memo)
## memo[n-2] = fib2(n-2, memo)
## return memo[n-1] + memo[n-2]''', number=100))
我在while
中使用了一个简单的fib
循环,而fib2
是一个递归的实现。{但事实证明fib2
特别慢。我想知道它为什么。是因为fib2
创建了大量的帧吗?我是否正确实施了fib2
?
感谢。
答案 0 :(得分:1)
将此简化的递归版本与原始迭代解决方案相对应 - 首先将递归限制提高约1%至10%:
def fib2(n, memo={0: None, 1: 1, 2: 1}):
if n in memo:
return memo[n]
previous = fib2(n - 1) # implicitly computes fib2(n - 2)
result = memo[n] = previous + memo[n - 2]
return result
我没有通过memo
作为递归的论据,因为我正在利用&#34;问题&#34;当默认参数设置为可以修改的结构时。
上述解决方案比第一次调用时我的机器上的原始迭代解决方案慢4.5倍 - 之后,memoization接管。我们可以在空间和空间上对此进行一点改进。时间,通过改变我们的记忆&#34;从字典到列表,因为所有键都是连续的整数:
def fib3(n, memo=[None, 1, 1]):
if n < len(memo):
return memo[n]
previous = fib3(n - 1) # implicitly computes fib3(n - 2)
result = previous + memo[-2]
memo.append(result)
return result
在我的机器上,第一次调用比迭代解决方案慢〜3倍。但是,我们可以使用递归更快速地做到:
def fib4(n, res=0, nxt=1):
if n == 0:
return res
return fib4(n - 1, nxt, res + nxt)
这比迭代解决方案慢〜2倍和/但没有记忆。在使用尾调用优化的语言(即不是Python)中,这可能会成为/ tie迭代。