LeetCode_70_爬楼梯

LeetCode_70_爬楼梯

考察内容:

动态规划

题目描述:

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

**注意:**给定 n 是一个正整数。

示例:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶

解题思路:

这道题目是典型的动态规划类型题目,首先我们要理解动态规划的思想:大事化小,小事化无。将大规模的问题转换为一个个小规模问题,并且保存这些小规模问题的答案,为最后求解大规模问题做准备。

这道题需要反向思考,即从后往前考虑。假设dp[i]表示爬上第 i i i层台阶所有的方案数,根据题目要求,我们一次只能爬1层台阶或者2层台阶。

  1. 如果我们选择最后一步只爬一层台阶,到达第 i i i层,则这种情况一共有dp[i-1]种方案,因为我们一定是从第 i − 1 i-1 i−1层爬1层台阶上来的,因此有dp[i-1]种方法。
  2. 如果我们选择最后一步爬两层台阶,到达第 i i i层,同理,这种情况共有dp[i-2]种方案,因为只能在dp[i-2]的每种方案末尾加上2阶才能实现爬两层台阶到达第 i i i层。

所以,由上面的分析我们就可以写出本题的状态转移方程:dp[i] = dp[i-1] + dp[i-2]

C++解题如下:

class solution{
public:
    int climbStairs(int n){
        vector<int>dp(n+1);//因为题目说n是正整数,而数组下标又从0开始,所以我们让dp数组比n大1
        //让dp数组从下标为1开始存储
        if(n <= 2){
            return n;
        }//1层台阶只有1种方法,2层台阶有2种方法,这相当于边界条件
        for(int i = 3; i < n + 1 ;i++){
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];//最后返回第n层台阶的所有方案即可。
    }
};

我们注意到,其实对于每个 n > 2 n > 2 n>2,它的方案数量都只跟 n − 1 n - 1 n−1与 n − 2 n - 2 n−2有关系,所以我们可以使用滑动窗口的方法使得额外开销从一个大小为 n + 1 n + 1 n+1的数组优化为O(1)

LeetCode_70_爬楼梯

如上图所示,p与q之和是r,在计算一次之后我们可以将第一次的p弹出窗口,将第一次的q放在p的位置,第一次的r放在q的位置,再计算第二个r…以此类推。这就像p、q、r是一个固定的窗口,我们在不断向后滑动它一样。如此一来我们只需要一个大小为3的窗口,而不用创建一个大小为n+1的dp数组了。

class solution{
public:
    int climbStairs(int n){
        if(n <= 2){
            return n;
        }
        int p = 1, q = 2, r = 0;//初始化滑动窗口
        for(int i = 3; i < n; i++){
            r = p + q;
            p = q; 
            q = r;//上面动画演示的过程,即窗口滑动的过程
        }
        return r;
    }
};
上一篇:极速办公如何在Excel中进行条件计数


下一篇:序列类型方法