难度:Easy ·
题目地址:https://leetcode.cn/problems/climbing-stairs/
标签:动态规划、滚动数组、斐波那契数列、数学 ·
进阶要求:能否使用仅 O(1) 空间复杂度实现解法
📝 题目描述
假设你正在爬楼梯。需要爬 n 阶才能到达楼顶。每次你只能爬 1 阶 或者 2 阶。请问有多少种不同的爬楼方法?
约束 :1 <= n <= 45
示例
| 示例 | 输入 | 输出 | 解释 |
|---|---|---|---|
| 1 | n = 2 |
2 |
① 1 阶 + 1 阶 ② 直接 2 阶 |
| 2 | n = 3 |
3 |
① 1+1+1 ② 1+2 ③ 2+1 |
| 3 | n = 4 |
5 |
--- |
💡 解题总览
本题本质为斐波那契数列变形,提供三种梯度解法:
- 解法一:暴力递归(入门直观,存在大量重复计算)
- 解法二:DP 数组动态规划(空间可优化,易懂)
- 解法三:滚动数组空间优化(最优解,O(1) 空间)
🔧 解法一:暴力递归(入门版)
🧠 解题思路
递推关系:要走到第 n 阶,最后一步只有两种选择:
- 走 1 阶 :前面需要走完
n-1阶 - 走 2 阶 :前面需要走完
n-2阶
公式 :
f(n) = f(n-1) + f(n-2)
递归终止条件:
n = 1:只有 1 种走法n = 2:只有 2 种走法
💻 完整代码(JavaScript)
javascript
var climbStairs = function(n) {
// 递归边界
if (n === 1) return 1;
if (n === 2) return 2;
// 递推公式
return climbStairs(n - 1) + climbStairs(n - 2);
};
⏱ 复杂度分析
- 时间复杂度:O(2ⁿ) ------ 大量重复递归计算,数值稍大就超时
- 空间复杂度:O(n) ------ 递归调用栈深度为 n
✅ 优缺点总结
| 优点 | 缺点 |
|---|---|
| 逻辑最简单,一眼看懂递推关系,适合理解基础思路 | 效率极低,n > 35 后运行极慢,无法通过大数据测试用例 |
🔧 解法二:DP 数组动态规划(标准 DP)
🧠 解题思路
- 用数组
dp存储每一层台阶的方案数,避免递归重复计算 dp[i]代表爬到第i阶楼梯的总走法- 状态转移方程:
dp[i] = dp[i-1] + dp[i-2] - 初始化边界:
dp[1] = 1,dp[2] = 2
💻 完整代码(JavaScript)
javascript
var climbStairs = function(n) {
if (n <= 2) return n;
const dp = new Array(n + 1);
dp[1] = 1;
dp[2] = 2;
for (let i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
};
⏱ 复杂度分析
- 时间复杂度:O(n) ------ 仅一次循环遍历
- 空间复杂度:O(n) ------ 开辟了长度为 n 的 dp 数组
✅ 优缺点总结
| 优点 | 缺点 |
|---|---|
| 无重复计算,效率稳定;DP 思想标准模板,便于拓展同类 DP 题 | 额外占用数组存储空间,没有达到进阶 O(1) 空间要求 |
🏆 解法三:滚动数组(位序迭代最优解)
🧠 解题思路
观察 DP 数组,计算 dp[i] 只需要 dp[i-1] 和 dp[i-2] 两个前值,不需要保存完整数组:
p:保存dp[i-2](前两阶方案数)q:保存dp[i-1](前一阶方案数)r:保存当前阶dp[i]的结果
每次循环滚动更新三个变量,全程不使用数组,空间压缩到常数级。
💻 完整代码(JavaScript)
javascript
var climbStairs = function(n) {
// p = f(i-2), q = f(i-1), r = f(i)
let p = 0, q = 0, r = 1;
for (let i = 1; i <= n; ++i) {
p = q;
q = r;
r = p + q;
}
return r;
};
⏱ 复杂度分析
- 时间复杂度:O(n) ------ 单层循环遍历
- 空间复杂度:O(1) ------ 仅固定 3 个变量,满足题目进阶要求
✨ 特点优势
- 时空双优,是本题最优官方推荐解法
- 代码极简,内存占用极小,大数据量性能稳定
- 滚动数组思想是动态规划空间优化的通用模板,可复用在各类 DP 题目中
📊 三种解法全面对比
| 解法 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|
| 暴力递归 | O(2ⁿ) | O(n) | 仅理解思路,无法提交大数据 |
| DP 数组 | O(n) | O(n) | 学习 DP 基础,逻辑直观 |
| 滚动数组 | O(n) | O(1) | 最优解,工程提交首选 |
⚠️ 核心易错点 & 核心知识点总结
🧩 核心知识点
- 斐波那契数列变形:爬楼梯是最经典的斐波那契应用题
- 动态规划滚动数组优化:DP 仅依赖前两项时,可抛弃数组只用变量迭代
- 递推思维:求解第 n 项结果,拆解为子问题 n-1、n-2 合并求解
🔥 高频易错点
| 易错点 | 说明 |
|---|---|
| 递归无记忆化 | 直接暴力递归会大量重复计算,直接超时 |
| 数组下标错位 | dp 数组初始化时容易混淆台阶下标,出现结果偏差 |
| 滚动变量更新顺序 | 必须先更新 p → q → r,颠倒顺序会覆盖原值,计算错误 |
| 边界条件漏判 | n=1、n=2 不做特判会出现初始变量计算异常 |