1. 题⽬链接:⾯试题08.01.三步问题
2. 题⽬描述
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 取题⽬范围内最⼤值时,⽹站会报错signed integer 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] 的值。
C++算法代码:
class Solution
{
public:
int waysToStep(int n)
{
if(n==1)
{
return 1;
}
//创造dp表
vector<int>dp(n+1);
//初始化
dp[0]=1,dp[1]=1,dp[2]=2;
//填表
for(int i=3;i<=n;i++)
{
dp[i]=((dp[i-1]+dp[i-2])%1000000007+dp[i-3])%1000000007;
}
//返回值
return dp[n];
}
};
Java算法代码:
class Solution
{
public int waysToStep(int n)
{
// 1. 创建 dp 表
// 2. 初始化
// 3. 填表
// 4. 返回值
1
2
3
4
5
6
7
8 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];
}
}