1.题目链接:
三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方 法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模1000000007。(1e7)
示例1:
输入:n = 3
输出:4
说明: 有四种走法
示例2:
输入:n = 5
输出:13
提示:
n范围在[1, 1000000]之间
3. 解法(动态规划)
算法思路
1. 状态表示
这道题可以根据「经验 + 题目要求」直接定义出状态表示:dp[i] 表示:到达 i 位置时,一共有多少种方法。
2. 状态转移方程
以 i 位置状态的最近的一步,来分情况讨论:
如果dp[i] 表示小孩上第 i 阶楼梯的所有方式,那么它应该等于所有上一步的方式之和:
- i.上一步上一级台阶,dp[i] += dp[i - 1] ;
- ii. 上一步上两级台阶,dp[i] += dp[i - 2] ;
- iii. 上一步上三级台阶,dp[i] += dp[i - 3] ;
综上所述,dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3] 。
需要注意的是,这道题目说,由于结果可能很大,需要对结果取模。
在计算的时候,三个值全部加起来再取模,即 (dp[i - 1] + dp[i - 2] + dp[i - 3]) % MOD 是不可取的,同学们可以试验一下,n 取题目范围内最大值时,网站会报错 signedinteger overflow 。对于这类需要取模的问题,我们每计算一次(两个数相加/乘等),都需要取一次模。否则,万一发生了溢出,我们的答案就错了。
3. 初始化
从我们的递推公式可以看出,dp[i] 在 i = 0, i = 1 以及 i = 2 的时候是没有办法进行推导的,因为 dp[-3]dp[-2] 或 dp[-1] 不是一个有效的数据。因此我们需要在填表之前,将 1, 2, 3 位置的值初始化。
根据题意,dp[1] = 1, dp[2] = 2, dp[3] = 4 。
4. 填表顺序
毫无疑问是「从左往右」。
5. 返回值
应该返回 dp[n] 的值。
Java算法代码:
class Solution {
public int waysToStep(int n) {
// 1.创建dp表
// 2.初始化
// 3.填表
// 4.返回值
int MOD = (int)1e9+7;
if(n == 1 || n==2) return n;
if(n == 3) return 4;
int[] dp = new int[n+1];
dp[1] = 1; dp[2]=2;dp[3]=4;
for(int i =4;i<=n;i++)
dp[i]=((dp[i-1]+dp[i-2])%MOD+dp[i-3])%MOD;
return dp[n];
}
}
运行结果:
动态规划:动态规划: 这道题目给定很多,状态的定义dp[i],以及状态转移方程dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3],初始化dp[1] = 1,dp[2] = 2,dp[3] = 4 。填表顺序(左 --> 右,以及返回值dp[n]。
---------------------------------------------------------------------------------------------------------------------------------
记住要做的几件事:
1.状态定义
2.状态转移方程
3.初始化
4.填表顺序
5.返回值