返回算法课程
动态规划基础

动态规划入门Dynamic Programming

把重复出现的子问题只计算一次,再用已知答案构造更大的答案。

30 分钟前置:数组 · 循环 · 递归基础

01先从一个问题出发

每次能走 1 级或 2 级台阶,到达第 n 级有几种不同走法?

一个具体的例子

3 级台阶有 1+1+1、1+2、2+1 共 3 种。最后一步不是 1 就是 2,因此 ways(3)=ways(2)+ways(1)。

02最直接的办法,为什么慢?

递归尝试最后一步走 1 级或 2 级。

暴力 · O(2ⁿ) 上界

ways(n−2) 等子问题会出现在多个分支中,被重复求解。

03一步步,推导出优化思路

1

发现可以复用的信息

定义状态:dp[i] 是恰好走到第 i 级的方法数。

2

建立可维护的状态

按最后一步分类,两类互斥且覆盖全部走法:dp[i]=dp[i−1]+dp[i−2]。

3

消除重复工作

设置 dp[0]=1,按台阶数递增计算,确保依赖已经就绪。

贯穿算法的不变量

计算 dp[i] 时,所有更小下标的状态已经正确计算。

04让每一步,都看得见

试着先预测下一步,再点击「下一步」验证。变量、动画与代码会同步变化。

Dynamic Programming交互演示
STEP 01 / 16
0
0
0
1
0
2
0
3
0
4
0
5
0
6
0
7

dp[i] = dp[i − 1] + dp[i − 2] · 橙色格正在计算

当前处理已处理 / 已确定未处理
01

dp[i] 表示到达第 i 级台阶的方法数,先全部初始化为 0。

dynamic_programming.py参考实现 · 当前第 2 行
正在载入代码编辑器…

动画展示参考实现的执行轨迹。切换语言时,当前操作会定位到对应代码行。

05复杂度,来自具体的工作量

时间复杂度
O(n)O(n)

只有 n+1 个不同状态,每个状态最多做一次加法,因此 O(n)。这里按定长整数运算计数;任意精度整数的位成本需要另算。

辅助空间
O(n)O(n)

表格保存 n+1 个状态。由于只依赖前两项,可进一步用两个变量压缩为 O(1) 辅助空间。

拖动 n,看看增长速度

06看到什么,应该想到它?

关键词只是线索,继续检查适用条件

07这些细节,容易踩坑

01

状态含义先说清

dp[i] 是方案数,不是最少步数;不同目标对应不同转移。

02

初始化也是模型一部分

dp[0]=1 表示唯一的空路径,否则无法统一计算最初状态。

03

先证明分类无重无漏

相加时两类走法必须互斥;状态不能遗漏影响未来的信息。

08把想法带进真实题目

先说出模式和适用条件,再开始写代码。

09不用背模板,回答这几个问题

01dp[0] 为什么等于 1?

02时间从指数降为线性的原因?

03能否只保存最近两项?

你已经走完了这次推导。

能用自己的话解释复杂度和不变量,再标记为掌握。

把知识连起来