深度思考爬楼梯问题,抽取一般过程,目标是对其变式题也能认出并且求解
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
https://leetcode.cn/problems/climbing-stairs/description/
示例:
思考一:为什么可以动态规划?
动态规划是指大规模问题,可以由它的小规模问题通过动态规划方程解出,而对本题来说,到达第 i 阶台阶的方案数可以由到达第 i-1 和 第 i-2的方案数求出,动态规划方程为:
dp[i] = dp[i-1] + dp[i-2]
解释:
上述动态规划方程中,dp 表示到达第 i 阶台阶的方案数,可以由第 i-1 阶台阶走一步到达第 i 阶台阶,也可由第 i-2 阶台阶走两步到达第 i 阶台阶,所以可写出如上的动态规划方程。
思考二: 如何初始化
dp[1] = 1;
dp[2] = 2;
解释:
由状态转移方程决定了初始化的值为 dp[1] 和 dp[2] (dp[i] = dp[i-1] + dp[i-2])
从第 0 台台阶迈一步到达第 1 阶台阶,因此到达第 1 阶台阶的方案有 1 个,同理,得到 dp[2] (由第 1 阶台阶迈一步 和 由第 0 阶台阶迈两步)
class Solution {
// 爬楼梯
public int climbStairs(int n) {
if(n == 1){
return 1;
} else if(n == 2){
return 2;
}
int dp[] = new int[n+1];
dp[1] = 1;
dp[2] = 2;
for(int i=3; i<n+1; i++){
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
}
给你整数 zero ,one ,low 和 high ,我们从空字符串开始构造一个字符串,每一步执行下面操作中的一种:
以上操作可以执行任意次。
如果通过以上过程得到一个 长度 在 low 和 high 之间(包含上下边界)的字符串,那么这个字符串我们称为 好 字符串。
https://leetcode.cn/problems/count-ways-to-build-good-strings/description/
让我们来看一下,本题和爬楼梯的区别和联系
dp[i] = dp[i - zero] + dp[i - one];
// 2466. 统计构造好字符串的方案数
public int countGoodStrings(int low, int high, int zero, int one) {
int mod = (int)(1e9 + 7);
int[] dp = new int[high + 1];
// 初始化
int step1 = Math.min(zero, one);
int step2 = Math.max(zero, one);
dp[step1] = 1;
dp[step2] = step2%step1==0 ? 2 : 1; // 走到 step2 的可能方案(直接走到step2、每次蹦跶step1直到蹦跶到step2)
// 遍历
for(int i=step1+1; i<=high; i++){
if(i > step2) { // 可以由 i - step1 和 i - step2 到达
dp[i] = (dp[i - step1] + dp[i - step2]) % mod;
} else if(i < step2){ // 只可以由 i - step1 到达
dp[i] = dp[i - step1];
}
}
int res = 0;
for(int i=low; i<=high; i++){ // 计算结果,在 low ~ high 之间的方案数
res = (res + dp[i]) % mod;
}
return res;
}
<总结> : 对一个问题,我们的求解关键是应该是抽丝剥茧,把问题捋清楚。像本文中的第二种变式题,它题目里的什么 0 1 就是误导,和 0 和 1 没关系,不要被误导,就是两种 step,给两种走不同 step 的方式!!!翻译过来就是走楼梯问题 ~~ 大家有不明白的欢迎评论区和我交流~~