0070.爬楼梯
难度:🟢 简单
标签:动态规划、记忆化搜索、数学
链接: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 阶
解题思路
核心思想
本题是一道非常经典的 动态规划 (Dynamic Programming) 入门题。问题的核心在于,要想到达第 n 阶楼梯,只有两种可能的方式:
从第
n-1阶爬1个台阶上来。从第
n-2阶爬2个台阶上来。
因此,到达第 n 阶的方法总数,就是到达第 n-1 阶的方法数与到达第 n-2 阶的方法数之和。这恰好是斐波那契数列的定义。
思路选择
动态规划(空间优化) 是解决此问题的最优思路。
我们可以定义
dp[i]为到达第i阶的方法数,那么状态转移方程就是dp[i] = dp[i-1] + dp[i-2]。进一步观察可以发现,计算
dp[i]时,我们只需要dp[i-1]和dp[i-2]的值。因此,没有必要创建一个完整的dp数组,只需用两个变量来滚动记录前两个状态的值即可,从而将空间复杂度从 O(n) 优化到 O(1)。
关键步骤
处理边界情况:当
n <= 2时,方法数就等于n,直接返回。初始化:初始化两个变量
first = 1(代表到达第 1 阶的方法数)和second = 2(代表到达第 2 阶的方法数)。循环迭代:从
i = 3开始循环到n。 a. 在循环中,计算到达第i阶的方法数temp = first + second。 b. 更新状态:将first更新为原来的second,将second更新为temp,为计算下一阶做准备。这个过程被称为“滚动数组”。返回结果:循环结束后,
second变量中存储的就是到达第n阶的方法总数,返回second。
代码实现
/**
* @param {number} n
* @return {number}
*/
var climbStairs = function (n) {
// 处理 n=1 和 n=2 的基本情况
if (n <= 2) {
return n;
}
// 初始化前两个状态
let first = 1; // 到达第1阶的方法数
let second = 2; // 到达第2阶的方法数
// 从第3阶开始迭代
for (let i = 3; i <= n; i++) {
// 当前阶的方法数是前两阶之和
let temp = first + second;
// 滚动更新状态
first = second;
second = temp;
}
// 返回最终结果
return second;
};
复杂度分析
时间复杂度:O(n) 我们只需要一个从 3 到 n 的循环,循环次数与 n 成正比。
空间复杂度:O(1) 我们只使用了
first,second,temp等常数个变量,与输入 n 的大小无关。
相关题目
总结
本题是动态规划思想的绝佳入门案例,它清晰地展示了如何找出状态转移方程,并在此基础上进行求解。从朴素递归到记忆化搜索,再到动态规划,最后通过“滚动数组”思想进行空间优化,完整地体现了算法优化的过程,是学习者必须掌握的经典模型。