计算第64个斐波纳契数时,第一个算法需要花费几个小时,而第二个算法则需要不到一秒钟。
为什么第二种算法的效率比第一种算法高得多?
它们看起来非常相似。
def fib_divide_recursion(n):
if n <= 2:
return n-1
else:
return fib_divide_recursion(n-1) + fib_divide_recursion(n-2)
def fib_linear_recursion(n, prev={}):
if n <= 2:
return n-1
try:
return prev[n]
except KeyError:
prev[n] = fib_linear_recursion(n - 1, prev) +
fib_linear_recursion(n - 2, prev)
return prev[n]
答案 0 :(得分:3)
第二种实现方式是使用“记忆”来记住先前计算的斐波那契值。
请考虑您要计算fib(5)
:首先必须计算fib(4)
和fib(3)
。 fib(4)
本身也需要您计算fib(3)
。实际上,对于每个斐波那契数字,您可以一次计算每个前面的斐波那契数字并将其存储(这是记忆方法)。或者,以较差的性能,即使您之前已经计算过,也可以重新计算所需的每个斐波那契数。显然,没有记忆,您将需要做成倍的工作,而且对于高斐波那契数,这确实有所作为。
答案 1 :(得分:1)
第一个算法的复杂度为O(2 ^ n)。
第二个将结果缓存在prev
中,因此对于给定的数字,它永远不会多次计算fib_linear_recursion
。它的复杂度是线性的O(n)。
有关更多详细信息,请参见this answer。
答案 2 :(得分:1)
第一种算法仅使用递归,而第二种算法使用动态编程,即带备忘录的递归。
如果您为第一算法绘制树,则会看到重复的节点。但是使用第二种算法,它将存储已经计算出的节点,因此程序不必一次又一次地为此计算