目标是做到:
看到题 → 直接匹配模板 → 改几行代码就能做
按 难度和面试频率排序。
一、线性 DP(最基础)
模板 1:爬楼梯型
最基础 DP。
特征:
- 每一步依赖前 1~2 个状态
python
dp = [0] * (n+1)
dp[0] = 1
dp[1] = 1
for i in range(2, n+1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
典型题:
- 爬楼梯
- 斐波那契
- 青蛙跳台阶
二、最大 / 最小值 DP
模板 2:最大子数组和
特征:
- 连续
- 以当前位置结尾
python
dp[0] = nums[0]
for i in range(1, n):
dp[i] = max(nums[i], dp[i-1] + nums[i])
return max(dp)
经典题:
- 最大子数组和
三、打家劫舍模板
模板 3:选 / 不选
python
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i in range(2, n):
dp[i] = max(
dp[i-1],
dp[i-2] + nums[i]
)
经典题:
- 打家劫舍
- 股票简化版
四、背包 DP 模板
模板 4:0-1 背包
python
for i in range(n):
for j in range(W, weight[i]-1, -1):
dp[j] = max(
dp[j],
dp[j-weight[i]] + value[i]
)
特点:
- 倒序遍历
经典题:
- 分割等和子集
- 目标和
模板 5:完全背包
python
for i in range(n):
for j in range(weight[i], W+1):
dp[j] = max(
dp[j],
dp[j-weight[i]] + value[i]
)
特点:
- 正序遍历
经典题:
- 零钱兑换
- 完全平方数
模板 6:背包求组合数
python
dp[0] = 1
for coin in coins:
for j in range(coin, amount+1):
dp[j] += dp[j-coin]
经典题:
- 零钱兑换 II
五、子序列 DP
模板 7:最长递增子序列(O(n²))
python
dp = [1] * n
for i in range(n):
for j in range(i):
if nums[j] < nums[i]:
dp[i] = max(dp[i], dp[j] + 1)
return max(dp)
模板 8:最长公共子序列
python
for i in range(1, m+1):
for j in range(1, n+1):
if s1[i-1] == s2[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = max(
dp[i-1][j],
dp[i][j-1]
)
模板 9:最长回文子序列
python
for i in reversed(range(n)):
for j in range(i+1, n):
if s[i] == s[j]:
dp[i][j] = dp[i+1][j-1] + 2
else:
dp[i][j] = max(
dp[i+1][j],
dp[i][j-1]
)
六、字符串编辑 DP
模板 10:编辑距离
python
for i in range(1, m+1):
for j in range(1, n+1):
if word1[i-1] == word2[j-1]:
dp[i][j] = dp[i-1][j-1]
else:
dp[i][j] = 1 + min(
dp[i-1][j],
dp[i][j-1],
dp[i-1][j-1]
)
七、网格 DP
模板 11:路径数量
python
for i in range(m):
for j in range(n):
dp[i][j] = dp[i-1][j] + dp[i][j-1]
模板 12:最小路径和
python
for i in range(m):
for j in range(n):
dp[i][j] = min(
dp[i-1][j],
dp[i][j-1]
) + grid[i][j]
八、状态机 DP
模板 13:股票问题
python
for i in range(1, n):
dp[i][0] = max(
dp[i-1][0],
dp[i-1][1] + price
)
dp[i][1] = max(
dp[i-1][1],
dp[i-1][0] - price
)
九、区间 DP
模板 14:区间合并
python
for length in range(2, n+1):
for i in range(n-length+1):
j = i + length - 1
for k in range(i, j):
dp[i][j] = min(
dp[i][j],
dp[i][k] + dp[k+1][j]
)
经典题:
- 戳气球
- 合并石头
十、DP + 位运算(进阶)
模板 15:状态压缩 DP
python
for mask in range(1<<n):
for i in range(n):
if mask & (1<<i):
dp[mask] = min(
dp[mask],
dp[mask^(1<<i)] + cost
)
经典题:
- TSP
- 最短 Hamilton 路
十一、DP + 树
模板 16:树形 DP
python
def dfs(node):
for child in node.children:
dfs(child)
dp[node] = combine(children)
经典题:
- 树上打家劫舍
十二、DP + 前缀
模板 17:分割 DP
python
for i in range(1, n+1):
for j in range(i):
dp[i] = min(
dp[i],
dp[j] + cost(j, i)
)
经典题:
- 单词拆分
- 回文分割
十三、DP + 数学
模板 18:Catalan 数
python
for i in range(2, n+1):
for j in range(i):
dp[i] += dp[j] * dp[i-1-j]
经典题:
- 不同二叉搜索树
十四、DP + 双序列
模板 19:最长公共子串(连续)
python
if s1[i] == s2[j]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = 0
十五、DP + 环
模板 20:环形 DP
python
# 拆成两个线性问题
case1 = rob(nums[:-1])
case2 = rob(nums[1:])
return max(case1, case2)
经典题:
- 打家劫舍 II
最重要的 DP 判断口诀
看到题先问 4 个问题:
1️⃣ 连续吗?
- 连续 → 子数组
2️⃣ 选不选?
- 选 / 不选 → 背包
3️⃣ 两个字符串?
- 字符串 DP
4️⃣ 区间操作?
- 区间 DP
最推荐掌握的 10 个 DP(面试命中率最高)
1 爬楼梯
2 打家劫舍
3 最大子数组和
4 分割等和子集
5 零钱兑换
6 最长递增子序列
7 最长公共子序列
8 编辑距离
9 最小路径和
10 戳气球