题意:
f(n)是Fibonacci数列.
求F(n)%1000000007的值.
求F(n)%1000000007的值.
方法一:
暴力枚举
思路:记忆化搜索Fibonacci数列,用map存储Fibonacci数列。三重循环模拟累加。
class Solution {
public:
/**
*
* @param n int整型
* @return int整型
*/
int MOD=1e9+7;
map<int,int> f;//存储fibonacci
int fibonacci(int x)//递归 O(n) 记忆化搜索
{
if(f[x])
return f[x];
if(x==1||x==2)
return 1;
return f[x]=(fibonacci(x-1)+fibonacci(x-2))%MOD;
}
int getSum(int n) {
int ans=0;
for(int i=1;i<=n;i++)//三重循环
{
for(int j=1;j<=i;j++)
{
for(int k=1;k<=j;k++)
{
ans=(ans+fibonacci(k))%MOD;
}
}
}
return ans;
}
};
时间复杂度:
,n是
,所以肯定超时。
空间复杂度:
,n是map存储的大小 和 递归栈的深度。
方法二:
矩阵快速幂
思路:
已知f(i)是fibonacci数列, 设g(i)是f(i)的前i项和,h(i)是g(i)的前i项和,F(i)是h(i)的前i项和。因而我们可以按照以下推导:
进而推理得到:
根据线性代数,可以得到矩阵乘法:
![]()
设推理得到的方阵为S,则。
所以。
。
先从整数的快速幂算法讲起,,同理,我们的矩阵快速幂
也可以按照将指数n拆分为二进制。
class Solution {
public:
int MOD=1e9+7;
vector<vector<long>> s={//公式推导出的s矩阵
{1, 1, 1, 1, 1},
{0, 1, 1, 1, 1},
{0, 0, 1, 1, 1},
{0, 0, 0, 1, 1},
{0, 0, 0, 1, 0}
};
vector<vector<long>> init_matrix={{4},{3},{2},{1},{1}};//n=2时的初始化矩阵A2
int getSum(int n) {
if(n==1)
return 1;
if(n==2)
return 4;
return mul(quickPow(s,n-2),init_matrix)[0][0]%MOD;//先算出S的(n-2)次方,再与A2矩阵相乘
}
vector<vector<long>> mul(vector<vector<long>> a,vector<vector<long>> b)//矩阵乘法
{
int num = b[0].size();
vector<vector<long>> c(5,vector<long>(num,0));
for(int i=0;i<5;i++)
{
for(int j=0;j<num;j++)
{
for(int k=0;k<5;k++)
{
c[i][j]=(c[i][j]+a[i][k]*b[k][j])%MOD;//矩阵相乘公式
}
}
}
return c;
}
vector<vector<long>> quickPow(vector<vector<long>> x,int n)//矩阵x的n次幂
{
vector<vector<long>> ans(5,vector<long>(5,0));
for(int i=0;i<5;i++)//初始化成单位矩阵
ans[i][i]=1;
while(n)
{
if(n&1)
{
ans=mul(ans,x);//如果该二进制位为1,则乘上该项
}
x=mul(x,x);//自乘
n>>=1;//右移一位
}
return ans;
}
};
时间复杂度:,矩阵的n次方,n是指数,拆分为二进制 。
空间复杂度:,存储的都是常数级别的矩阵。



京公网安备 11010502036488号