DP表开(m+1)×(n+1)是因为dpi表示word1[0..i-1]→word2[0..j-1]的最小操作数,需额外行列处理空串边界:dp0=j、dpi=i。

为什么 editDistance 的 DP 表要开 (m+1) × (n+1)
因为状态定义是:dp[i][j] 表示将 word1[0..i-1] 变成 word2[0..j-1] 的最少操作数。下标从 0 开始,空字符串对应长度为 0,所以需要多留一行一列来表示“空串 → 非空串”或“非空串 → 空串”的初始状态。
如果只开 m × n,就无法自然表示 word1 或 word2 为空时的边界情况,后续递推会越界或逻辑错乱。
-
dp[0][j] = j:把空串变成长度为j的串,只能插入j次 -
dp[i][0] = i:把长度为i的串变为空串,只能删除i次 - 所有初始化必须在循环前完成,不能依赖未定义值
替换、插入、删除三种操作怎么映射到状态转移
核心在于看 word1[i-1] 和 word2[j-1] 是否相等(注意下标偏移):
- 相等:不需要操作,直接继承
dp[i-1][j-1] - 不相等:从三个可能操作中取最小值:
- 替换:
dp[i-1][j-1] + 1(改掉末尾字符) - 删除:
dp[i-1][j] + 1(删掉word1的末尾,再处理剩下部分) - 插入:
dp[i][j-1] + 1(在word1末尾插入一个字符匹配word2[j-1])
- 替换:
注意:这三者没有优先级,必须全部计算后取 min;漏掉任意一种都会导致结果偏大。
立即学习“C++免费学习笔记(深入)”;
空间优化时为什么只能滚动两行而非一维数组
因为状态转移依赖左上、正上、正左三个位置:dp[i-1][j-1]、dp[i-1][j]、dp[i][j-1]。若用一维 dp[j],更新 dp[j] 时 dp[j-1] 已被覆盖(代表新行),而 dp[j] 原值(旧行)又刚被覆盖,dp[j-1] 的旧值也丢了——dp[i-1][j-1] 彻底不可恢复。
- 正确做法是用两个一维数组:
prev和curr,分别存第i-1行和第i行 - 每次迭代后交换指针:
swap(prev, curr),避免拷贝开销 - 若硬要用单数组,必须额外缓存
prev[j-1](即左上角值),否则一定出错
常见错误:输入含空格或控制字符时结果异常
编辑距离算法本身对字符无假设,但实际使用中容易踩坑:
- 用
std::cin >> a >> b读入会跳过空格,导致含空格的字符串被截断;应改用std::getline(std::cin, a) - Windows 下换行符是
"\r\n",若文件读入未处理\r,它会被当作普通字符参与计算,使距离虚高 - C++ 字符串比较区分大小写,
"Abc"和"abc"编辑距离为 1,不是 0;如需忽略大小写,须提前统一转小写 - Unicode 多字节字符(如中文)在
std::string中按字节算,会导致单个汉字被拆成多个“字符”参与 DP,结果无意义;此时应改用std::u32string或 UTF-8 解码后处理码点
真正难的不是写出三重 if,而是确认你传进去的两个 std::string 确实是你以为的那个字符串。


















