在算法面试中,爬楼梯问题(LeetCode 第 70 题)是一道经典的动态规划入门题。本文将带你从零开始,用 JavaScript 实现一个高效、易读的解法,并深入探讨其背后的斐波那契数列思想与工程落地细节。无论你是准备面试还是巩固基础,这篇文章都能给你清晰的思路和可复用的代码模板。
问题理解与模式识别
题目描述很简单:你正在爬楼梯,每次可以走 1 步或 2 步,问到达第 n 阶有多少种不同的方法?例如,n = 3 时,有 (1+1+1)、(1+2)、(2+1) 三种走法。
这个问题的本质是 斐波那契数列变种。到达第 i 阶的方法数 F(i) 等于 F(i-1)(再走 1 步)加上 F(i-2)(再走 2 步)。边界条件:F(1) = 1,F(2) = 2。
在 JavaScript 中,我们通常用函数形式实现,如 F(n) = F(n-1) + F(n-2)、F(1)=1、F(2)=2。
⚙️ 算法选择与工程落地
对于爬楼梯问题,最直接的解法是 动态规划(迭代法),时间复杂度 O(n),空间复杂度 O(1)。为什么不用递归?因为递归会导致大量重复计算,而迭代法只需两个变量即可完成。
JavaScript 工程落地考虑:
- 函数定义:通常使用
function climbStairs(n)或箭头函数。LeetCode 平台可能提供类结构,但多数情况下就是普通函数。 - 整数范围:JavaScript 的
number类型是双精度浮点数,其安全整数范围(Number.MAX_SAFE_INTEGER)远超第 45 阶斐波那契数,所以number类型足够。 - 变量声明:使用
let声明可变变量,const声明不可变变量。 - 边界处理:
n=1,n=2。 - 注释:采用 JSDoc 风格(
/** ... */),提升可维护性。
✅ 这种设计思路同样适用于 TypeScript、Python、Java 等语言,只需调整类型声明和语法即可。
编写 JavaScript 代码
下面给出完整的实现,包含详细的 JSDoc 注释和边界处理:
/**
* @param {number} n 楼梯总阶数 (1 <= n <= 45)。
* @return {number} 到达楼顶的不同方法数。
*
* @description
* 思路:该问题是一个经典的斐波那契数列变种。
* 到达第 i 阶的方法数,等于到达第 i-1 阶(再走1步)与到达第 i-2 阶(再走2步)的方法数之和。
* 令 F(i) 为到达第 i 阶的方法数。
* 递推关系:F(i) = F(i-1) + F(i-2)。
*
* 边界条件:
* F(1) = 1 (只可能走 1 步)
* F(2) = 2 (可能走 1+1 或 2)
*
* 采用动态规划(迭代法)实现,空间复杂度为 O(1),时间复杂度为 O(n)。
* JavaScript 的 number 类型足以处理 F(45) 的结果。
*/
var climbStairs = function(n) {
// 处理基本边界情况
if (n === 1) {
return 1;
}
if (n === 2) {
return 2;
}
// 使用 O(1) 空间复杂度的动态规划
// prev2 存储 F(i-2) 的值,prev1 存储 F(i-1) 的值
let prev2 = 1; // 对应 F(1)
let prev1 = 2; // 对应 F(2)
// 从第 3 阶开始迭代计算,直到第 n 阶
// 循环执行 n - 2 次
for (let i = 3; i <= n; i++) {
// 计算当前阶数的方法数
const currentWays = prev1 + prev2;
// 更新 prev2 和 prev1,为下一轮迭代做准备
prev2 = prev1; // 原来的 F(i-1) 变为下一轮的 F(i-2)
prev1 = currentWays; // 新计算出的 F(i) 变为下一轮的 F(i-1)
}
// 循环结束后,prev1 中存储的就是 F(n) 的值
return prev1;
};
测试与代码审查
让我们测试几个关键用例:
- 示例 1:
n = 2,n === 2返回 2。✅ 正确。 - 示例 2:
n = 3,prev2 = 1,prev1 = 2,i = 3:currentWays = 2 + 1 = 3.prev2 = 2,prev1 = 3. 循环结束,返回prev1(3)。✅ 正确。 - 边界情况:
n = 1已在代码中处理。
代码风格审查:
- 函数定义使用
var climbStairs = function(n) { ... };或function climbStairs(n) { ... }结构。LeetCode 提供了var climbStairs = function(n) { ... };的模板。 - 变量命名
prev2,prev1,currentWays清晰明了。 - JSDoc 注释(
/** ... */)包含@param,@return,@description,是 JavaScript 的标准实践。 let和const的使用:let用于变量prev1,prev2(会改变),const用于currentWays(在循环内部计算一次,不改变)。===:使用严格相等比较,避免隐式类型转换,是 JS 的良好实践。
⚠️ 如果你使用 TypeScript,可以给参数和返回值加上类型注解,进一步提升代码健壮性。例如 function climbStairs(n: number): number。
最终检查与总结
代码逻辑正确,通过所有示例。变量类型 number 足够存储结果。最终提交的代码模板如下:
/**
* @param {number} n 楼梯总阶数 (1 <= n <= 45)。
* @return {number} 到达楼顶的不同方法数。
*
* @description
* 思路:该问题是一个经典的斐波那契数列变种。
* 到达第 i 阶的方法数,等于到达第 i-1 阶(再走1步)与到达第 i-2 阶(再走2步)的方法数之和。
* 令 F(i) 为到达第 i 阶的方法数。
* 递推关系:F(i) = F(i-1) + F(i-2)。
*
* 边界条件:
* F(1) = 1 (只可能走 1 步)
* F(2) = 2 (可能走 1+1 或 2)
*
* 采用动态规划(迭代法)实现,空间复杂度为 O(1),时间复杂度为 O(n)。
* JavaScript 的 number 类型足以处理 F(45) 的结果。
*/
var climbStairs = function(n) {
// 处理基本边界情况
if (n === 1) {
return 1;
}
if (n === 2) {
return 2;
}
// 使用 O(1) 空间复杂度的动态规划
// prev2 存储 F(i-2) 的值,prev1 存储 F(i-1) 的值
let prev2 = 1; // 对应 F(1)
let prev1 = 2; // 对应 F(2)
// 从第 3 阶开始迭代计算,直到第 n 阶
// 循环执行 n - 2 次
for (let i = 3; i <= n; i++) {
// 计算当前阶数的方法数
const currentWays = prev1 + prev2;
// 更新 prev2 和 prev1,为下一轮迭代做准备
prev2 = prev1; // 原来的 F(i-1) 变为下一轮的 F(i-2)
prev1 = currentWays; // 新计算出的 F(i) 变为下一轮的 F(i-1)
}
// 循环结束后,prev1 中存储的就是 F(n) 的值
return prev1;
};
JavaScript 版快闪赛的特点总结:
- 函数定义:使用
var functionName = function(params) {...}或function functionName(params) {...}结构。 - 变量声明:
let和const的使用,强调了变量的可变性。 - JSDoc 注释:符合 JavaScript 标准的注释格式,提高代码可读性和可维护性。
- 严格相等
===:比==更安全,避免隐式类型转换。
如果你对动态规划感兴趣,还可以尝试用 Python 或 C++ 实现同样的逻辑,对比不同语言的语法差异。

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。
浙公网安备 33010602011771号