LeetCode 70 爬楼梯:彻底搞懂 for _ in range(3, n + 1),顺便入门动态规划
很多人第一次刷 LeetCode 70《爬楼梯》时,代码能看懂,但总会卡在这样一句:
for _ in range(3, n + 1):
尤其是两个问题:
- 为什么从 3 开始?
- 为什么用
_而不是i?
事实上,这句代码背后不仅涉及 Python 循环语法,更隐藏着动态规划最经典的递推思想。
今天就结合爬楼梯这道题,把它彻底讲明白。
题目描述
假设你正在爬楼梯。
每次你可以爬:
- 1 个台阶
- 2 个台阶
问:爬到第 n 阶一共有多少种不同的方法?
例如:
n = 2
1 + 1
2
共 2 种
n = 3
1 + 1 + 1
1 + 2
2 + 1
共 3 种
先找规律
很多动态规划题,第一步不是写代码,而是找规律。
第1阶
只有一种走法:
1
所以:
f(1) = 1
第2阶
有两种走法:
1 + 1
2
所以:
f(2) = 2
第3阶
最后一步有两种可能:
最后走 1 阶
说明前面已经到达第2阶。
方法数:
f(2)
最后走 2 阶
说明前面已经到达第1阶。
方法数:
f(1)
因此:
f(3) = f(2) + f(1)
即:
f(3) = 2 + 1 = 3
第4阶
同样的思路:
f(4) = f(3) + f(2)
第5阶
f(5) = f(4) + f(3)
规律已经出现:
f(n) = f(n-1) + f(n-2)
这其实就是斐波那契数列。
动态规划递推公式
核心公式:
f(n) = f(n-1) + f(n-2)
含义是:
到达第 n 阶的方法数:
= 到达第 n-1 阶的方法数
到达第 n-2 阶的方法数
为什么只需要两个变量
很多同学刚学动态规划时会写数组:
dp = [0] * (n + 1)
实际上这道题不需要。
因为计算当前状态时:
f(n)
只依赖:
f(n-1)
f(n-2)
更早的数据已经没用了。
所以只保留两个变量即可。
a = f(n-2)
b = f(n-1)
然后不断向后滚动。
为什么是 range(3, n + 1)
代码里通常这样写:
a, b = 1, 2
for _ in range(3, n + 1):
a, b = b, a + b
很多人第一次看到会疑惑。
为什么从3开始
因为:
f(1) = 1
f(2) = 2
已经提前知道了。
也就是:
a = 1
b = 2
已经完成初始化。
后面真正需要计算的是:
第3阶
第4阶
...
第n阶
因此循环从3开始。
为什么是 n+1
因为 Python 的 range 是左闭右开区间。
例如:
range(3, 6)
实际生成:
3
4
5
不会生成:
6
所以如果想循环到 n:
range(3, n + 1)
必须写成:
n + 1
为什么用 _
很多新手会问:
for _ in range(...):
这里的 _ 是什么意思?
其实:
_
只是一个普通变量名。
下面两种写法完全等价:
for i in range(3, n + 1):
for _ in range(3, n + 1):
区别在于:
i
表示:
这个变量后面可能会用到。
而:
_
表示:
我根本不关心循环变量是什么,只想循环这么多次。
这是 Python 的一种编码习惯。
模拟运行过程
假设:
n = 5
初始化:
a = 1
b = 2
表示:
a -> 第1阶方法数
b -> 第2阶方法数
第一次循环
计算第3阶:
a, b = b, a + b
变成:
a = 2
b = 3
表示:
a -> f(2)
b -> f(3)
第二次循环
计算第4阶:
a = 3
b = 5
表示:
a -> f(3)
b -> f(4)
第三次循环
计算第5阶:
a = 5
b = 8
表示:
a -> f(4)
b -> f(5)
循环结束:
return b
得到:
8
完整代码
class Solution:
def climbStairs(self, n: int) -> int:
if n == 1:
return 1
if n == 2:
return 2
a, b = 1, 2
for _ in range(3, n + 1):
a, b = b, a + b
return b
时间复杂度分析
时间复杂度
O(n)
只遍历一次。
空间复杂度
O(1)
只使用了两个变量。
相比数组动态规划:
O(n)
空间更加优秀。
总结
这道题本质上是动态规划最经典的入门题。
核心只有三步:
- 找出递推公式
f(n)=f(n-1)+f(n-2)
- 初始化边界
f(1)=1
f(2)=2
- 用两个变量滚动更新状态
a,b = b,a+b
而代码中的:
for _ in range(3,n+1)
含义其实非常简单:
- 从第3阶开始计算;
- 一直算到第n阶;
_表示循环变量没有实际用途;- 每循环一次,就向后递推一阶。
理解了这一题,后面像斐波那契数列、使用最小花费爬楼梯、打家劫舍等动态规划题目,都会发现本质上是在做同一件事情:利用已知状态推导未知状态。

1487

被折叠的 条评论
为什么被折叠?



