70. 爬楼梯(完全背包)
题目链接:
假设你正在爬楼梯。需要 n
阶你才能到达楼顶。
每次你可以爬 1
或 2
个台阶。你有多少种不同的方法可以爬到楼顶呢?
示例 1:
输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
示例 2:
输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
-
1 <= n <= 45
解题思路
本题的第一种利用斐波那契的解法在
其实,选择”爬1个台阶,爬2个台阶“就相当于选择物品1或物品2,并且物品1和物品2的数量是无限的。如果还可以选择”爬3个台阶,...,爬n个台阶“就相当于选择物品3...物品n。并且该题还属于排列问题,因为”1 阶 + 2 阶“和”2 阶 + 1 阶“是不相同的。
运用动态规划五部曲解决问题:
-
确定dp数组以及其下标的含义
dp[j]
表示有dp[j]
种方法爬到有i
个台阶的楼顶 -
确定递推公式
将可以选择爬的楼梯数记录在method数组中,即 method= {1,2}。
于是得到递推公式为:
dp[j] = dp[j] + dp[j - method[i]]
-
dp数组的初始化
dp[0] = 1
下标非0的
dp[j]
初始化为0,这样累计加dp[j - method[i]]
的时候才不会影响真正的dp[j]
-
确定遍历顺序
在
总结:
-
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
-
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
-
-
举例推导dp数组(略)
C++
class Solution { public: int climbStairs(int n) { vector<int> dp(n + 1, 0); vector<int> method = {1, 2}; dp[0] = 1; for (int j = 0; j <= n; j++) { for (int i = 0; i < method.size(); i++) { if (j >= method[i]) { dp[j] += dp[j - method[i]]; } } } return dp[n]; } };
JavaScript
/** * @param {number} n * @return {number} */ var climbStairs = function(n) { const method = [1, 2]; const dp = new Array(n + 1).fill(0); dp[0] = 1; for (let j = 0; j <= n; j++) { for (let i = 0; i < method.length; i++) { if (j >= method[i]) { dp[j] += dp[j - method[i]]; } } } return dp[n]; };