0 题目描述
leetcode原题链接:斐波那契数
1 原始递归
下图表示了 fib(5) 计算过程的递归树:
class Solution:
def fib(self, N: int) -> int:
if N <= 1: return N
return self.fib(N-1) + self.fib(N-2)
复杂度分析
时间复杂度:
O
(
2
N
)
O(2^N)
O(2N)。这是计算斐波那契数最慢的方法。因为它需要指数的时间。
空间复杂度:
O
(
N
)
O(N)
O(N),在堆栈中我们需要与
N
N
N 成正比的空间大小。该堆栈跟踪 fib(N) 的函数调用,随着堆栈的不断增长如果没有足够的内存则会导致 StackOverflowError。
2 自底向上进行迭代:动态计算
自底向上通过迭代计算斐波那契数的子问题并存储已计算的值,通过已计算的值进行计算。减少递归带来的重复计算。
class Solution:
def fib(self, N: int) -> int:
if N <= 1: return N
x, y = 0, 1
for i in range(2, N+1):
x, y = y, x+y
return y
复杂度分析
时间复杂度:
O
(
N
)
O(N)
O(N)。
空间复杂度:
O
(
1
)
O(1)
O(1),保存最后 2个斐波那契数,不使用数组。
3 性能优化
1、预计算 31 个斐波那契数:
初始化一个数组用于保存斐波那契数,并初始化前 2个斐波那契数字。i 从 2 循环到 31,每一步计算出一个新的斐波那契数。
2、从数组中检索所需的斐波那契数。
class Fibna:
def __init__(self):
n = 31
self.nums = nums = [0] * n
nums[0], nums[1] = 0, 1
for i in range(2, n):
nums[i] = nums[i-1] + nums[i-2]
class Solution:
fibna = Fibna()
def fib(self, N: int) -> int:
return self.fibna.nums[N]
复杂度分析
时间复杂度:
O
(
1
)
O(1)
O(1),预计算31个斐波那契数字,并在数组中检索。
空间复杂度:
O
(
1
)
O(1)
O(1),存储31个斐波那契数字的数组。
还有一种基于 Binet 公式进行计算的方法,直接使用通项公式,时间和空间复杂度均为 O ( 1 ) O(1) O(1)。