题目:输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下:F(0) = 0, F(1) = 1, F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
答案需要取模 1e9+7(1000000007)
解法一:矩阵快速幂
基本思路
斐波那契数列递推式:f(n)=f(n-1)+f(n-2)
且由矩阵乘法可推出下列公式:
[
f
(
n
)
f
(
n
−
1
)
]
=
[
1
1
1
0
]
[
f
(
n
−
1
)
f
(
n
−
2
)
]
=
[
1
1
1
0
]
[
1
1
1
0
]
[
f
(
n
−
2
)
f
(
n
−
3
)
]
=
…
…
=
[
1
1
1
0
]
n
−
1
[
f
(
1
)
f
(
0
)
]
\begin{bmatrix} f(n)\\ f(n-1) \end{bmatrix}= \begin{bmatrix} 1&1\\ 1&0 \end{bmatrix} \begin{bmatrix} f(n-1)\\ f(n-2) \end{bmatrix}= \begin{bmatrix} 1&1\\ 1&0 \end{bmatrix} \begin{bmatrix} 1&1\\ 1&0 \end{bmatrix} \begin{bmatrix} f(n-2)\\ f(n-3) \end{bmatrix}=……= \begin{bmatrix} 1&1\\ 1&0 \end{bmatrix} ^{n-1} \begin{bmatrix} f(1)\\ f(0) \end{bmatrix}
[f(n)f(n−1)]=[1110][f(n−1)f(n−2)]=[1110][1110][f(n−2)f(n−3)]=……=[1110]n−1[f(1)f(0)]
于是,只需求矩阵[1,1,1,0]的n-1次方,再计算其与[f(1),f(0)]的乘积即可。
整数快速幂的代码如下:
long long Pow(long long base, long long expo,long long mod)
{
long long pow=1;
while (expo)
{
if (expo & 1) (pow *= base) %= mod;
(base *= base) %= mod;
expo >>= 1;
}
return pow;
}
复杂度
时间复杂度:O(log n)
空间复杂度:O(1)
具体实现
class Solution {
public:
long long ans[2][2]; //{1,0,1,0}
long long base[2][2]; //{1,1,1,0}
long long f[2][1]; //{F(1),F(0)}
long long mod;
void matrix_mul(long long a[2][2],long long b[2][2]){ //矩阵乘法(a*=b)%=mod
long long t00=a[0][0],t01=a[0][1],t10=a[1][0],t11=a[1][1];
long long w00=b[0][0],w01=b[0][1],w10=b[1][0],w11=b[1][1];
(a[0][0]=t00*w00+t01*w10)%=mod;
(a[0][1]=t00*w01+t01*w11)%=mod;
(a[1][0]=t10*w00+t11*w10)%=mod;
(a[1][1]=t10*w01+t11*w11)%=mod;
}
void matrix_pow(int expo){ //矩阵快速幂 base的expo次方
while(expo){
if(expo&1) matrix_mul(ans,base); //(ans*=base)%=mod
matrix_mul(base,base); //(base*=base)%mod
expo>>=1;
}
}
int fib(int n) { // 原理:[f(n),f(n-1)] = [1,1,1,0]的n-1次方 * [f(1),f(0)]
ans[0][0]=1; ans[0][1]=0; ans[1][0]=0; ans[1][1]=1;
base[0][0]=1; base[0][1]=1; base[1][0]=1; base[1][1]=0;
f[0][0]=1; f[1][0]=0;
mod=1000000007;
if(n==0) return 0;
matrix_pow(n-1);//计算base[1,1,1,0]的n-1次方
//计算 base[1,1,1,0]的n-1次方 * [f(1),f(0)]
(ans[0][0]=ans[0][0]*f[0][0]+ans[0][1]*f[1][0])%=mod;
(ans[1][0]=ans[1][0]*f[0][0]+ans[1][1]*f[1][0])%=mod;
return ans[0][0];
}
};
解法二:动态规划
基本思路
- 状态定义: 一维数组dp,dp[ i ]代表斐波那契数列第 i 个数字
- 转移方程: dp[i+1] = dp[i] + dp[i-1]
- 初始状态: dp[1] = 1, dp[0] =0
但由于本题结果只由前两个状态决定,可以用普通变量代替一维数组,以降低空间复杂度。
复杂度
时间复杂度:O(n)
空间复杂度:O(1)
具体实现
class Solution {
public:
int fib(int n) {
//a相当于dp[i-1],b相当于dp[i]
long long a=0,b=1,mod=1000000007;
if(n==0) return 0;
for(int i=1;i<=n-1;i++){
int temp=b;
(b=a+b)%=mod;
a=temp;
}
return b;
}
};