矩阵快速幂(爬楼梯)
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
一. 动态规划
经典动态规划类型题目,这种问题关键在于如何将问题规模缩小并且找到边界
即找到状态转移方程和边界条件
很显然跳第n阶的方法,会等于n-2阶和n-1阶之和
即状态转移方程为dp[n]=dp[n-1]+dp[n-2]
边界为dp[1]=1,dp[2]=2,与斐波那契数列递推基本一致
具体执行可以正向顺序递推,也可以反向递归
之所以能写成dp[n]=dp[n-1]+dp[n-2]进行动态规划和递推
这是求解路径的时候,求的是一个全排列的问题,先跳一步还是先跳两步是两种不同的方案
像凑零钱、背包问题则没有方向和顺序,对应的是一个全组合问题
//其实质上进行的是
for (int i = 1; i <= n; i++){
for (int j = 0; j < 2; j++){
int step = steps[j];
if ( i < step ) continue;// 台阶少于跨越的步数
DP[i] = DP[i] + DP[i-step];
}
//步长位于内循环
//放到外层可以变成求解组合数的问题
for (int j = 0; j < 2; j++){
int step = steps[j];
for (int i = 1; i <= n; i++){
if ( i < step ) continue;// 台阶少于跨越的步数
DP[i] = DP[i] + DP[i-step];
}
}
反向递归
class Solution {
public:
int jumpFloor(int number) {
if(number==1) return 1;
if(number==2) return 2;
return jumpFloor(number-1)+jumpFloor(number-2);
}
};
正向递推
class Solution {
public:
int climbStairs(int n) {
vector<int> dp(n+1);//类似C语言数组,初始化为0
dp[1]=1;
dp[2]=2;
for(int i=3;i<=n;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n];
}
};
二. 矩阵快速幂
接着快速计算矩阵M的n次幂即可得出答案
int climbStairs(int n) {
vector<vector<int>> matrix = {{1,1},{1,0}};
vector<vector<int>> left = fastpower(matrix,n-1);
vector<int> right = {2,1};
vector<int> res = mutiply(left,right);
return res[1];
}
三. 矩阵运算
const int MOD = INT_MAX;
vector<vector<int>> mutiply(vector<vector<int>>& left,vector<vector<int>> &right){
int m = left.size(); int n = right.size();
vector<vector<int>> res(m,vector<int>(m));
for(int i=0;i<m;i++) //遍历left 的 m行
for(int j=0;j<m;j++) //遍历right 的 m列
for(int k=0;k<n;k++) //遍历相乘的每一个数
res[i][j] = (res[i][j] + ((long long)left[i][k]*right[k][j])%MOD)%MOD;
return res;
}
vector<int> mutiply(vector<vector<int>>& left,vector<int> &right){
int m = left.size(); int n = right.size();
vector<int> res(m);
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
res[i] = (res[i] + ((long long)left[i][j]*right[j])%MOD)%MOD;
return res;
}
vector<vector<int>> identify(int m){
vector<vector<int>> res(m,vector<int>(m));
for(int i=0;i<m;i++)
res[i][i] = 1;
return res;
}
vector<vector<int>> fastpower(vector<vector<int>> cur, int n){
int m = cur.size();
vector<vector<int>> res = identify(m);//初始化单位矩阵
while(n){//进行快速幂运算
if(n&1) res = mutiply(res,cur);
cur = mutiply(cur,cur);//倍增
n>>=1;
}
return res;
}