#19488. 二维DP题单简介
二维DP题单简介
你好!看到你的成绩单,作为教练,我首先要肯定你的状态定义能力——你在 1D DP 和基础背包问题上的逻辑非常清晰。
你目前遇到的瓶颈是 “多序列/字符串匹配类 DP”。这类问题的核心在于决策的同步性:是两个序列各推进一步(斜对角线),还是其中一个序列先停下而另一个推进一步(水平或垂直)。
为了帮你突破这个瓶颈,我为你制定了以下针对性方案。
第一部分:洛谷针对性补课题单
建议按照以下顺序练习,重点体会“状态从哪里来”:
- P2758 编辑距离(核心加练):直接针对你错的第 7 题,强制练习三种操作的逻辑转换。
- P1439 【模板】最长公共子序列:针对第 9 题。注意这题有 和 两种写法,先吃透 的二维转移。
- P1140 相似基因序列:这是编辑距离的变种,你会发现它本质上是在填一张得分表,通过这题区分“匹配成功”和“与空字符匹配”。
- P1216 [USACO1.5] 数字三角形:虽然简单,但它是所有 2D 路径 DP 的鼻祖,用来巩固“上方/左上方”的来源判断。
- P1006 传纸条:进阶练习。这题涉及两条路径同时走,是对“多维度状态转移”的终极考验。
第二部分:预备知识点总结
在做这些题之前,请确保你理解以下概念:
- 笛卡尔坐标系下的状态依赖:理解
dp[i][j]在二维表中的几何位置(左、上、左上)。 - 边界初始化:字符串 DP 中,当一个字符串长度为 0 时,另一个字符串需要全部删除/添加的操作数(即
dp[i][0]和dp[0][j]的含义)。 - 滚动数组优化:二维 DP 如何压缩成一维,从而优化空间复杂度(从 到 )。
第三部分:启发式思维引导(草稿纸上的推理)
现在,拿出一张草稿纸。我们以 “最长公共子序列 (LCS)” 为例,模拟你的思考过程。
1. 绘制状态表
假设字符串 A = ABC, B = AC。我们在纸上画一个 4x3 的方格(包含第 0 行/列)。
| "" | A | B | C | |
|---|---|---|---|---|
| "" | 0 | 0 | ||
| A | ? | |||
| C | ||||
2. 启发式提问与图形思考
情景 A:当 A[i] == B[j] 时(例如 A[1]='A', B[1]='A')
- 思考:这两个字母匹配成功了,它们是不是共同占用了 LCS 的一个长度?
- 动作:在格子里画一个斜向右下的箭头 ↘️。
- 推导:既然这两个字母都用了,那长度就是“去掉这两个字母后的结果” + 1。
- 结论:
dp[i][j] = dp[i-1][j-1] + 1(来自左上角)。
情景 B:当 A[i] != B[j] 时(例如 A[2]='B', B[2]='C')
- 思考:这两个字母不相等,没法配对。那我可以尝试把 A 的 'B' 扔掉,或者把 B 的 'C' 扔掉。
- 动作:画一个向右 ➡️ 和向下 ⬇️ 的箭头。
- 推导:
- 扔掉 A 的 'B':看
dp[i-1][j](上方) - 扔掉 B 的 'C':看
dp[i][j-1](左方)
- 扔掉 A 的 'B':看
- 结论:取两者最大值
max(dp[i-1][j], dp[i][j-1])。
3. 复杂度分析思考
- 时间复杂度:我们在填一个 的表格,每个格子只算一次。复杂度 。
- 优化建议:如果 达到 ,必须考虑 算法(利用 LIS 转化,见模板题 P1439)。
- 空间复杂度:默认 。
- 优化建议:观察发现计算
dp[i]只需要dp[i-1]的数据。可以用 “滚动数组” 将空间压至 。
- 优化建议:观察发现计算
第四部分:读题关键词总结
在 DP 题目中,一旦看到以下关键词,就要警惕是否需要 二维状态转移:
- “两个序列/两个字符串”:
- 含义:大概率需要
dp[i][j],其中 表示第一个序列的进度, 表示第二个。
- 含义:大概率需要
- “子序列 (Subsequence)” vs “子串 (Substring)”:
- 子序列:不要求连续(转移往往涉及
max(dp[i-1][j], dp[i][j-1]))。 - 子串:必须连续(如果不匹配,状态可能直接重置为 0)。
- 子序列:不要求连续(转移往往涉及
- “最小操作次数” / “编辑”:
- 含义:通常涉及 3 种来源(增、删、改),对应左、上、左上。
- “刚好匹配” 或 “配对”:
- 含义:这是对角线转移(左上角)的强烈信号。
教练寄语:
你在做题时,可以在草稿纸上画一个小方块,标出 (i, j)。每次转移前问自己:“如果我想求这个格子的最优解,我的最后一步动作是只消耗 A、只消耗 B、还是同时消耗 A 和 B?” 只要分清这三点,二维 DP 就不再是难点。加油!