标准的斐波那契数列计算使用递归实现时,重复计算体现在每次计算斐波那契数时,它会重复计算相同的子问题。例如,当计算F(5)
时,递归算法会计算F(4)
和F(3)
。然而,在计算F(4)
时,它又会计算F(3)
和F(2)
,而在计算F(3)
时,它又会计算F(2)
和F(1)
。这样,F(3)
和F(2)
都被计算了多次,而这种重复是完全没有必要的。
以下是一个标准的斐波那契数列的递归实现,以及它在计算F(5)时是如何展开的:
int fibonacci(int n) {
if (n <= 1) {
return n;
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
计算F(5)
时的递归调用树如下:
fibonacci(5)
fibonacci(4) fibonacci(3)
fibonacci(3) fibonacci(2)
fibonacci(2) fibonacci(1)
fibonacci(1)
fibonacci(0)
从上面的调用树中可以看出,F(3)
被计算了两次,F(2)
被计算了两次。随着 n
的增大,这种重复计算的次数会急剧增加,导致时间复杂度呈指数级增长。这就是为什么标准递归实现的时间复杂度是O(2^n)
,而使用带备忘录的递归可以将时间复杂度降低到O(n)
。