入门动态规划(DP),关键不是"多刷题",而是建立一套可复用的思考框架。
一、先搞清楚:什么问题该用 DP?
出现这些特征,优先考虑 DP:
1️⃣ 最优子结构
问题可以拆成子问题,并且子问题的最优解能组成整体最优解
👉 例:
- 最长递增子序列
- 最小路径和
2️⃣ 重叠子问题
暴力递归会重复计算
👉 典型特征:
python
f(n) = f(n-1) + f(n-2)
3️⃣ "状态"可以被定义
你能用一个变量/数组描述当前局面
二、万能解题五步法(核心)
这是你要刻在脑子里的模板:
🧠 Step 1:定义状态(最关键!)
👉 问:dp[i] 或 dp[i][j] 表示什么?
比如:
dp[i]:到第 i 个位置的最优解dp[i][j]:前 i 个物品,容量 j 的最优值
👉 ⚠️ 80% 的人死在这里
🔁 Step 2:写状态转移方程
👉 问:当前状态如何从之前推出来?
比如:
python
dp[i] = dp[i-1] + dp[i-2]
或者(背包):
python
dp[i][j] = max(
dp[i-1][j],
dp[i-1][j-w[i]] + v[i]
)
🧱 Step 3:初始化
👉 最容易被忽略但最容易错
python
dp[0] = ?
dp[1] = ?
🔄 Step 4:遍历顺序
👉 很多人不会写DP其实是这里错了
- 正序 / 逆序
- 是否会覆盖数据
例如:
python
for i in range(n):
或
python
for i in range(n, -1, -1):
🎯 Step 5:返回结果
python
return dp[n]
三、从"不会"到"会"的关键训练路径
我给你一条最短学习路径👇
🟢 Level 1:一维 DP(最基础)
题型
- 斐波那契
- 爬楼梯
- 打家劫舍
👉 核心:
dp[i] 只依赖前几个状态
🟡 Level 2:二维 DP
题型
- 网格路径
- 最小路径和
👉 核心:
python
dp[i][j] = 上 + 左
🟠 Level 3:背包问题(DP核心)
题型
- 0/1 背包
- 完全背包
👉 这是 DP 的"操作系统内核"
🔴 Level 4:序列 DP(难点)
题型
- 最长递增子序列(LIS)
- 最长公共子序列(LCS)
⚫ Level 5:区间 DP / 状态压缩
👉 比较高级(可以后面再说)
四、一个完整例子(带思路)
🧩 爬楼梯
每次可以走 1 或 2 步,问多少种走法
✅ Step 1:定义状态
python
dp[i] = 到第 i 阶的方法数
✅ Step 2:转移
python
dp[i] = dp[i-1] + dp[i-2]
✅ Step 3:初始化
python
dp[1] = 1
dp[2] = 2
✅ Step 4:代码
python
def climbStairs(n):
if n <= 2:
return n
dp = [0] * (n + 1)
dp[1], dp[2] = 1, 2
for i in range(3, n + 1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
五、工程化理解(非常重要)
你可以把 DP 当成:
👉 一个"缓存 + 递推系统"
本质就是:
- 把递归 → 改成表格
- 把重复计算 → 变成查表
六、你可能卡住的点(提前避坑)
❌ 1:状态定义模糊
👉 解法:强制写一句中文解释 dp 含义
❌ 2:不会写转移方程
👉 解法:
先写暴力递归,再改 DP
❌ 3:遍历顺序错
👉 解法:
画表格(非常有效)
七、给你一个"快速提升方案"(很实用)
如果你想 3 天入门:
Day 1
- 爬楼梯
- 打家劫舍
Day 2
- 最小路径和
- 不同路径
Day 3
- 0/1 背包(核心)
八、如果你想更猛一点(进阶建议)
你可以把 DP 提升到"Agent级思维":
👉 自动拆解问题:
- 状态空间
- 转移图
- 依赖关系 DAG
甚至可以写一个:
🔥 "自动推导 DP 状态机的工具"