LeetCode 70 爬楼梯:彻底搞懂 `for _ in range(3, n + 1)`,顺便入门动态规划

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)

空间更加优秀。


总结

这道题本质上是动态规划最经典的入门题。

核心只有三步:

  1. 找出递推公式
f(n)=f(n-1)+f(n-2)
  1. 初始化边界
f(1)=1
f(2)=2
  1. 用两个变量滚动更新状态
a,b = b,a+b

而代码中的:

for _ in range(3,n+1)

含义其实非常简单:

  • 从第3阶开始计算;
  • 一直算到第n阶;
  • _ 表示循环变量没有实际用途;
  • 每循环一次,就向后递推一阶。

理解了这一题,后面像斐波那契数列、使用最小花费爬楼梯、打家劫舍等动态规划题目,都会发现本质上是在做同一件事情:利用已知状态推导未知状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值