思路:
题目的主要信息:
- 斐波那契数列
,其中
- 求
方法一:暴力解法(超时)
具体做法:
使用动态规划求斐波那契数列前n项的值,然后三个循环按照公式相加。
class Solution {
public:
int mod = 1e9 + 7;
int getSum(int n) {
vector<int> dp(n + 1, 0); //动态规划求前n个斐波那契数列
dp[1] = 1;
for(int i = 2; i <= n; i++)
dp[i] = (dp[i - 2] + dp[i - 1]) % mod; //公式相加
int res = 0;
for(int i = 1; i <= n; i++) //三层遍历,按照公式
for(int j = 1; j <= i; j++)
for(int k = 1; k <= j; k++)
res = (res + dp[k]) % mod;
return res;
}
};复杂度分析:
- 时间复杂度:
,求所有的斐波那契数列为
,最后的公式三层循环
- 空间复杂度:
,辅助数组dp记录前
项斐波那契数列
方法二:矩阵快速幂
具体做法:
上述做法加得太过于复杂,毕竟这是相当于一个数列相加,我们用数列求和的方式对其化简一下:
得到如上图所示的递推公式以后,我们可以将其换成矩阵写法:
于是我们只需要得到中间那个数字矩阵的次方,然后再与后面一个矩阵相乘,第一个元素即是我们要求的
,其中
.
为了快速求中间那个矩阵的的次方,我们可以采用矩阵快速幂。参考数字的快速幂 ,矩阵也有类似的算法:
可以使用类似二分的方法来计算矩阵的幂,这样我们只需要计算即可。
class Solution {
public:
int mod = 1e9 + 7;
vector<vector<long>> base = { //由刚刚推算出的基础矩阵
{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>> Mul(vector<vector<long>>& x, vector<vector<long>>& y){ //x矩阵乘上y矩阵
int n = y[0].size(); //查看第二维是1还是5
vector<vector<long>> res(5, vector<long>(n, 0));
for(int i = 0; i < 5; i++){ //遍历相乘相加
for(int j = 0; j < n; j++){
for(int k = 0; k < 5; k++){
res[i][j] = (res[i][j] + x[i][k] * y[k][j]) % mod;
}
}
}
return res;
}
vector<vector<long>> Pow(vector<vector<long>>& x, int k){ //矩阵快速幂
vector<vector<long>> res(5, vector<long>(5, 0));
for(int i = 0; i < 5; i++)
res[i][i] = 1; //初始化为单位矩阵
while(k){
if(k & 1)
res = Mul(res, base);
k = k >> 1;
base = Mul(base, base);
}
return res;
}
int getSum(int n) {
if(n == 1) //优先判断1和2
return 1;
if(n == 2)
return 4;
vector<vector<long>> a = base;
vector<vector<long>> b = {{4},{3},{2},{1},{1}};
vector<vector<long>> c = Pow(a, n - 2); //基础矩阵的n-2次方
return (int)Mul(c, b)[0][0]; //二者相乘
}
};复杂度分析:
- 时间复杂度:
,矩阵快速幂一共调用
次乘法运算,乘法运算为复杂度为
,故总时间复杂度为
- 空间复杂度:
,所有辅助矩阵要么是
要么就是
,属于常数空间

京公网安备 11010502036488号