LeetCode/爬楼梯


描述
假设你正在爬楼梯。需要 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 dp[46]{0};//用备忘录存储减少重复计算
    int climbStairs(int n) {
        if(n<=1) return 1;
        if(dp[n]>0) return dp[n];
        else{
            dp[n]=climbStairs(n-1)+climbStairs(n-2);
            return dp[n];
        }
    }
};

正向递推

点击查看代码
class Solution {
public:
    int climbStairs(int n) {
        vector dp(n+2);//类似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次幂即可得出答案,运用到线代里面的矩阵分解


--数学方法通项公式--