七十二.编辑距离
<br />题目中的三种操作本质上其实可以分为
- 给 word1 插入一个字符:如果知道 word1 到 word2-1 的编辑次数 a,那么显然只需要 a+1 就能够得到结果
- 给 word2 插入一个字符:如果知道 word1 到 word2-1 的编辑次数 b,那么显然只需要 b+1 就能够得到结果
- 修改 word1 的一个字符:如果知道 word1 到 word2-1 的编辑次数 c,那么显然只需要 c+1 就能够得到结果
因此 word1 到 word2 的编辑距离应该是 min(a+1, b+1, c+1)
根据这个本质,我们可以继续拆分出更小的子编辑次数,直到 word1 和 word2 为空串,下面以 horse 和 ros 为例
- word1 为空,我们就知道需要编辑 3 次,才能达到 word2 的长度
- word2 为空,我们就知道需要编辑 5 次,才能达到 word1 的长度
因此,可以设 dp[i][j] 表示 word1[1…i] 位置转换成 word[1…j] 需要的最少编辑次数
当 word1[i]==word2[j] 时,dp[i-1][j-1]==dp[i][j]
否则 dp[i][j] = min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + 1
- dp[i][j-1] 为 word1 的前 i 个字符和 word2 的前 j - 1 个字符编辑距离的子问题。即对于 word2 的第 j 个字符,我们在 word1 的末尾添加了一个相同的字符,那么 dp[i][j] 最小可以为 dp[i][j-1] + 1
- dp[i-1][j] 为 word1 的前 i - 1 个字符和 word2 的前 j 个字符编辑距离的子问题。即对于 word1 的第 i 个字符,我们在 word2 的末尾添加了一个相同的字符,那么 dp[i][j] 最小可以为 dp[i-1][j] + 1
- dp[i-1][j-1] 为 word1 前 i - 1 个字符和 word2 的前 j - 1 个字符编辑距离的子问题。即对于 word2 的第 j 个字符,我们修改 word1 的第 i 个字符使它们相同,那么 dp[i][j] 最小可以为 dp[i-1][j-1] + 1。特别地,如果 word1 的第 i 个字符和 word2 的第 j 个字符原本就相同,那么我们实际上不需要进行修改操作。在这种情况下,dp[i][j] 最小可以为 dp[i-1][j-1]
因此不难写出代码
class Solution {
public int minDistance(String word1, String word2) {
int l1 = word1.length();
int l2 = word2.length();
int[][] dp = new int[l1+1][l2+1];
for (int i = 0; i <= l1; i++) {
dp[i][0] = i;
}
for (int i = 0; i <= l2; i++) {
dp[0][i] = i;
}
for (int i = 1; i <= l1; i++) {
for (int j = 1; j <= l2; j++) {
if(word1.charAt(i - 1) == word2.charAt(j - 1)){
dp[i][j] = dp[i-1][j-1];
}else{
dp[i][j] = Math.min(Math.min(dp[i-1][j-1], dp[i][j-1]), dp[i-1][j])+1;
}
}
}
return dp[l1][l2];
}
}
