原题
一、题目内容 简单
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
示例1:
输入:n = 2 输出:2 解释:有两种方法可以爬到楼顶。
- 1 阶 + 1 阶
- 2 阶
示例2:
输入:n = 3 输出:3 解释:有三种方法可以爬到楼顶。
- 1 阶 + 1 阶 + 1 阶
- 1 阶 + 2 阶
- 2 阶 + 1 阶
提示:
- 确定 dp 数组的含义
dp[i]:爬到第 i 阶,有 dp[i] 种方法
- 递推公式
到第 1 阶,只能走 1 步,故是 dp[1] = 1
到第 2 阶,dp[2] 等于第 1 阶走一步,或者第 0 阶走两步,dp[2] = dp[1] + dp[0]
到第 3 阶,dp[3] 等于第 2 阶走一步,或者第 1 阶走两步,dp[3] = dp[2] + dp[1]
到第 n 阶,dp[n] 等于第 n - 1 阶走一步,或者第 n - 2 阶走两步,dp[n] = dp[n-1] + dp[n-2]
- dp 数组初始化
dp[0] = dp[1] = 1
三、具体代码
/*** @param {number} n* @return {number}*/var climbStairs = function (n) {// dp[i]:爬到第 i 阶,有 dp[i] 种方法const dp = [1, 1]for (let i = 2; i <= n; i++) {dp[i] = dp[i - 1] + dp[i - 2]}return dp[n]};
四、其他解法
题目变体
一、题目内容 中等
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 ~ m 个台阶。你有多少种不同的方法可以爬到楼顶呢?
示例1:
输入: m = 3,n = 3 输出: 4 解释:有三种方法可以爬到楼顶。
- 1 阶+ 1 阶 + 1 阶
- 1 阶 + 2 阶
- 2 阶 + 1 阶
- 3 阶
示例2:
输入: m = 7, n = 4 解释:有八种方法可以爬到楼顶。
- 1 阶+ 1 阶 + 1 阶 + 1 阶
- 1 阶 + 2 阶 + 1 阶
- 2 阶 + 1 阶 + 1 阶
- 1 阶 + 1 阶 + 2 阶
- 2 阶 + 2 阶
- 1 阶 + 3 阶
- 3 阶 + 1 阶
- 4 阶
二、解题思路
- 确定dp数组以及下标的含义
**dp[i]**:爬到有 i 个台阶的楼顶,有**dp[i]**种方法。
- 确定递推公式
本题呢,dp[i]有几种来源,dp[i - 1],dp[i - 2],dp[i - 3] 等等,即:dp[i - j]
那么递推公式为:dp[i] += dp[i - j]
- dp 数组如何初始化
既然递归公式是 dp[i] += dp[i - j],那么dp[0]一定为 1,dp[0]是递归中一切数值的基础所在,如果dp[0]是 0 的话,其他数值都是 0 了。
下标非 0 的 dp[i] 初始化为0,因为 dp[i] 是靠 dp[i-j] 累计上来的,dp[i]本身为 0 这样才不会影响结果
- 确定遍历顺序
这是背包里求排列问题,即:1、2 步 和 2、1 步都是上三个台阶,但是这两种方法不一样!
所以需将 target 放在外循环,将 nums 放在内循环。
每一步可以走多次,这是完全背包,内循环需要从前向后遍历。
三、具体代码
const climbStairs = function (n, m) {// dp[i]:爬到第 i 阶有 dp[i] 种方法const dp = new Array(n + 1).fill(0)// 初始化 dp 数组dp[0] = 1// 遍历背包for (let i = 1; i <= n; i++) {// 遍历物品for (let j = 1; j <= m; j++) {if (i >= j) dp[i] += dp[i - j]}}return dp[n]}
