70 爬楼梯
记录:
分析: 关键在于公式的理解
f ( x ) = f ( x − 1 ) + f ( x − 2 ) f(x)=f(x-1)+f(x-2) f(x)=f(x−1)+f(x−2)
- 一共有x阶台阶,在最后登上第x阶时有两种方案,一种是只需要跨一阶,另一种是需要跨两阶;
- 而在需要跨一阶时,已经位于第x-1阶;在需要跨两阶时,位于第x-2阶。
- f(x)代表跨到第x阶时一共有几种方案
滚动数组思想
class Solution { //第一版AC代码
int f[46];
public:
int climbStairs(int n) {
f[0]=f[1]=1;
for(int i=2;i<=n;i++)
f[i]=f[i-1]+f[i-2];
return f[n];
}
};
-
由上可看到,申请了46个数组空间,若N较大实际上比较费空间
-
实际上不需要将过程中每一阶的方案一一存下来,只需要迭代,滚动数组获得n阶时的具体方案数即可。
-
由低阶的时候不断迭代加进去就可以得到最新的方案值,一直叠加即可,滚动只保持最新的前三个数组的元素即可
-
修改如下:
class Solution { //滚动数组修改版
public:
int climbStairs(int n) {
int a=b=1,c=1;
for(int i=2;i<=n;i++)
{
c=a+b;//存两者之和 等价于f[i]=f[i-1]+f[i-2];
a=b; //更新 a 实际就是新f[i-1]=旧f[i]
b=c;//更新b 实际就是新f[i]=c
}
return c;
}
};
-
数学思想: 矩阵次幂
-
适用于n比较大的情况
-
使用矩阵乘法,考虑到本题涉及到的变量其实只需要2*2大小的矩阵就可,在n较大时,无论是矩阵的空间开销还是矩阵乘法时间开销相加起来总归比n-1次迭代的时间复杂度要有效率,并且此处可用快速幂,使时间复杂度降到
O ( l o g n ) 其中 n 指的是指数大小 O(logn) 其中n指的是指数大小 O(logn)其中n指的是指数大小
-
快速幂
-
理解关键:
- 将乘法次数减少到一半
- 确定指数为0时,即初态;
- 每次相乘其实就是平方,a*a=c c*c=d
- 若指数为偶数,则只需要递归计算n/2次幂的结果,最后平方
- 若指数为奇数,则需要递归(n-1)/2次幂的结果,平方后,再乘上一次幂(初态);
- 所以时间复杂度降为O(log n),参考二叉树
//题解里 C++实现快速幂部分 以矩阵乘法为例
//快速幂可适用于 一维数组、正常一个数皆可,关键在于思想的理解
vector<vector<long long>> multiply(vector<vector<long long>>& a, vector<vector<long long>>& b) {//实现矩阵乘法
vector<vector<long long>> c(2, vector<long long>(2));
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j];
}
}
return c;
}
//实现快速幂
vector<vector<long long>> matrixPow(vector<vector<long long>> a, int n) {
vector<vector<long long>> ret = { {1, 0}, {0, 1} };//单位矩阵的构造,key
while (n > 0) {
if ((n & 1) == 1) { //很关键,利用与运算,既暂存上一步的结果,又实现指数是奇数则最后再乘上一次初矩阵
ret = multiply(ret, a);
}
n >>= 1; //右移一位,表示n/2;
a = multiply(a, a); //矩阵平方后更新矩阵,即实现每一次乘法都实现平方
}
return ret;
}
本题 矩阵次幂思想解法 (c++官方题解理解)
class Solution {
public:
vector<vector<long long>> multiply(vector<vector<long long>> &a, vector<vector<long long>> &b) {
vector<vector<long long>> c(2, vector<long long>(2));
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j];
}
}
return c;
}
vector<vector<long long>> matrixPow(vector<vector<long long>> a, int n) {
vector<vector<long long>> ret = {{1, 0}, {0, 1}};
while (n > 0) {
if ((n & 1) == 1) {
ret = multiply(ret, a);
}
n >>= 1;
a = multiply(a, a);
}
return ret;
}
int climbStairs(int n) {
vector<vector<long long>> ret = {{1, 1}, {1, 0}}; //由本题递归公式得出来的对应的初矩阵
vector<vector<long long>> res = matrixPow(ret, n);//进行快速幂
return res[0][0];//取结果矩阵的第一个元素,则为F(n)
}
};
- 总结:
- 关于快速幂的与运算,移位运算如果有计算机组成原理相关底层知识会更有助于理解。
- 虽然这个题是DP比较基础的题,但是相关的思路可以学习,扎实基础。