题意:
斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
给定 n ,请计算 F(n)
示例:
示例1:
**输入:**n = 2
**输出:**1
**解释:**F(2) = F(1) + F(0) = 1 + 0 = 1
示例2:
**输入:**n = 3
**输出:**2
**解释:**F(3) = F(2) + F(1) = 1 + 1 = 2
示例3:
**输入:**n = 4
**输出:**3
**解释:**F(4) = F(3) + F(2) = 2 + 1 = 3
提示:
0 <= n <= 30
我的解法:
思路:
1.创建一个fn_list列表,用于保存从f0,f1,…,fn,并将f0 = 0, f1 = 1存入列表。
- 如果n≤1,返回 fn_list的第n项;
如果n>1,根据公式F(n) = F(n - 1) + F(n - 2),依次求出f2,…,fn-1,并存入fn_list。返回fn_list[n-1] + fn_list[n-2]。
class Solution:
def fib(self, n: int) -> int:
fn_list = [0,1]
#判断n是否大于1
if n <= 1:
return fn_list[n]
#当n大于1时
i = 2
while i < n:
f = fn_list[i-1] + fn_list[i-2]
fn_list.append(f)
i += 1
return fn_list[n-1] + fn_list[n-2]
分析:
- 时间复杂度:O(n)。
- 空间复杂度:O(n)。
提交结果 | 执行时间 | 内存消耗 |
---|---|---|
通过 | 40 ms | 14.8 MB |
2.注意:不要漏掉n≤1的情况。
官方解法
### 方法一:动态规划**滑动窗口**
#### 思路:
斐波那契数的边界条件是 F(0)=0 和 F(1)=1。当 n>1时,每一项的和都等于前两项的和,因此有如下递推关系:
F(n)=F(n-1)+F(n-2)
由于斐波那契数存在递推关系,因此可以使用动态规划求解。动态规划的状态转移方程即为上述递推关系,边界条件为 F(0) 和 F(1)。
根据状态转移方程和边界条件,可以得到时间复杂度和空间复杂度都是 O(n) 的实现。由于 F(n) 只和 F(n-1)与 F(n-2) 有关,因此可以使用「滚动数组思想」把空间复杂度优化成 O(1)。如下的代码中给出的就是这种实现。
class Solution:
def fib(self, n: int) -> int:
if n < 2:
return n
p, q, r = 0, 0, 1
for i in range(2, n + 1):
p, q = q, r
r = p + q
return r
#### 复杂度分析
- 时间复杂度:O(n)。
- 空间复杂度:O(1)。
执行用时:40 ms;内存消耗:14.8 MB。
### 方法二:矩阵快速幂
方法一的时间复杂度是 O(n)。使用矩阵快速幂的方法可以降低时间复杂度。
首先我们可以构建这样一个递推关系:
[ 1 1 1 0 ] [ F ( n ) F ( n − 1 ) ] = [ F ( n ) + F ( n − 1 ) F ( n ) ] = [ F ( n + 1 ) F ( n ) ] \left[\begin{array}{ll}1 & 1 \\ 1 & 0\end{array}\right]\left[\begin{array}{c}F(n) \\ F(n-1)\end{array}\right]=\left[\begin{array}{c}F(n)+F(n-1) \\ F(n)\end{array}\right]=\left[\begin{array}{c}F(n+1) \\ F(n)\end{array}\right] [1110][F(n)F(n−1)]=[F(n)+F(n−1)F(n)]=[F(n+1)F(n)]
因此:
[ F ( n + 1 ) F ( n ) ] = [ 1 1 1 0 ] n [ F ( 1 ) F ( 0 ) ] \left[\begin{array}{c}F(n+1) \\ F(n)\end{array}\right]=\left[\begin{array}{ll}1 & 1 \\ 1 & 0\end{array}\right]^{n}\left[\begin{array}{c}F(1) \\ F(0)\end{array}\right] [F(n+1)F(n)]=[1110]n[F(1)F(0)]
令:
M = [ 1 1 1 0 ] M=\left[\begin{array}{ll}1 & 1 \\ 1 & 0\end{array}\right] M=[1110]
因此只要我们能快速计算矩阵 M 的 n 次幂,就可以得到 F(n) 的值。如果直接求取 M^n,时间复杂度是 O(n),可以定义矩阵乘法,然后用快速幂算法来加速这里 M^n的求取。
class Solution:
def fib(self, n: int) -> int:
if n < 2:
return n
q = [[1, 1], [1, 0]]
res = self.matrix_pow(q, n - 1)
return res[0][0]
def matrix_pow(self, a: List[List[int]], n: int) -> List[List[int]]:
ret = [[1, 0], [0, 1]]
while n > 0:
if n & 1:
ret = self.matrix_multiply(ret, a)
n >>= 1
a = self.matrix_multiply(a, a)
return ret
def matrix_multiply(self, a: List[List[int]], b: List[List[int]]) -> List[List[int]]:
c = [[0, 0], [0, 0]]
for i in range(2):
for j in range(2):
c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j]
return c
#### 复杂度分析:
- 时间复杂度:O(logn)。
- 空间复杂度:O(1)。