1.题目描述:
假设你正在爬楼梯。需要n阶你才能到达楼顶。每次你可以爬1或2个台阶。你有多少种不同的方法可以爬到楼顶呢?
2.动态规划:
只有1个台阶,一种方法。只有2个台阶,两种方法。3个台阶,分解为1个台阶的走法(走2步到3)加上2个台阶的走法(走一步到3),以此类推dp[n] = dp[n - 1] + dp[n - 2],就是斐波那契数列,见leetcode509. 斐波那契数。
class Solution {
public int climbStairs(int n) {
if (n <= 2) return n;
int[] dp = new int[]{1, 2};
int res = 0;
for (int i = 3; i <= n; i++) {
res = dp[0] + dp[1];
dp[0] = dp[1];
dp[1] = res;
}
return res;
}
}
二刷:更容易理解dp数组。
class Solution {
public int climbStairs(int n) {
if (n <= 2) return n;
int[] dp = new int[n + 1];
dp[0] = 1;//代表1阶楼梯
dp[1] = 1;//代表2阶楼梯
for (int i = 2; i < n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
}
补充一下完全背包的解法,详见leetcode518. 零钱兑换 II及前面背包问题的解法。
class Solution {
public int climbStairs(int n) {
int[] dp = new int[n + 1];
dp[0] = 1;
for (int i = 0; i <= n; i++) {//排列问题,先遍历背包
for (int j = 1; j <= 2; j++) {//直接把索引当成物品1和2,并且只要把2改成m,即可解决这类不管一次爬几阶的爬楼梯问题
if (i >= j) dp[i] += dp[i - j];
}
}
return dp[n];
}
}
二刷完全背包:
class Solution {
public int climbStairs(int n) {
int[] dp = new int[n + 1];
dp[0] = 1;
int[] goods = new int[]{1, 2};
for (int i = 0; i < n + 1; i++) {//1+2和2+1情况不同,实际为排列问题,先遍历背包
for (int j = 0; j < goods.length; j++) {
if (i >= goods[j]) dp[i] += dp[i - goods[j]];
}
}
return dp[n];
}
}