【动态规划】 LeetCode #面试题 08.01. 三步问题

题目链接:

LeetCode #面试题 08.01. 三步问题

题目描述:

#面试题 08.01. 三步问题

三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模1000000007。

示例1:

输入:n = 3
输出:4
说明: 有四种走法
示例2:

输入:n = 5
输出:13
提示:

n范围在[1, 1000000]之间

通过次数7,771 | 提交次数22,802

分析:

1.这个题是爬楼梯问题的变形,关于经典的 “爬楼梯” 问题,动态规划的入门题,文章链接如下:

【动态规划入门】LeetCode #70 爬楼梯

题目本身难度不大,满足动态规划思想求解的条件。设 dp[i] 为到达第 i 个台阶的方法数,最后一步可以选择上一阶、两阶、三阶:dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]。

初始化:
dp[0] = 1(如果 dp 为0,代表无法到达,故此处应为 1);
dp[1] = 1;
dp[2] = 2。

2.这个题最大的坑,在于题目中的这句话:结果可能很大,你需要对结果模1000000007。

这是笔试题中很常见的一种题型,从题目来看,n 的范围在 [1, 1000000] 之间,我们测一下 n 为最大值,结果是负数。

这个原因是 dp 的值可能会超过 int 的范围(大约在 n=42 时),一旦超出范围(溢出),数值就不再准确,因为改变了最高位,所以可能出现变为负数的情况。

为了避免超过 int 范围,我们需要进行取模运算(此处代码用的是取余运算,这两者不完全相同,但是本题不会涉及到两者的区别,感兴趣可以自行查阅资料,),dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3],其中任何一个加法都可能导致超过 int 的范围,故应在每步都做取模运算。

3.动态规划在空间复杂度上的优化老套路:每次计算 dp[i] 只会用到前面三个的数据,不必创建一维数组 dp[]

代码:

先上提交截图:
【动态规划】 LeetCode #面试题 08.01. 三步问题_第1张图片
优化后代码如下:

/*
*动态规划,设 dp[i] 为到达第 i 个台阶的方法数
*dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3],最后一步可以选择上一阶、两阶、三阶
*dp[0] = 1(如果 dp 为0,代表无法到达,故此处应为 1), dp[1] = 1, dp[2] = 2
*n范围在[1, 1000000]之间,也就是说 dp 很可能会超出 int 的范围
*一旦超出范围(溢出),数值就不再准确,变为负数
*优化:每次计算 dp[i] 只会用到前面三个的内容,不必创建一维数组
*/
class Solution {
    public int waysToStep(int n) {
        if(n < 3) return n;
        int dp = 0;
        int prev1 = 1; //初始化
        int prev2 = 1; 
        int prev3 = 2;
        for(int i = 3; i <= n; i++){//为避免超出 int 范围,进行取模运算
            dp = ((prev1 + prev2) %  1000000007 + prev3) % 1000000007;
            prev1 = prev2;
            prev2 = prev3;
            prev3 = dp;
        }
        return dp;
    }
}

你可能感兴趣的:(动态规划,LeetCode)