编辑距离是双字符串输入的DP应用中的一个经典问题,其题面为
给定两个单词word1和word2,其长度分别为N1和N2, 返回将 word1 转换成 word2 所使用的最少操作数。你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
实例:
word1 = "horse", word2 = "ros"
答案是3,将第一个字符h替换为r,删除第三个字符r,删除最后的e。
解题思路:
我们使用F(i, j)作为DP表达式,其中i和j分别是两个字符串的数组下标,F(i, j)返回的是word1[i:N1]和word2[j:N2]之间的编辑距离。F(i, j)的返回值有以下几种情况,
- i>=N1,j>=N2,此时两个字串都为空,F(i, j)返回0
- i>=N1,j< N2,此时只有第一个字串为空,因此F(i, j)返回N2 - j个删除
- i<N1,j>= N2,此时只有第二个字串为空,因此F(i, j)返回N1 - i个删除
- i<N1,j<N2,且word1[i]和word2[j]相同,此时F(i, j)返回F(i + 1, j + 1)
- i<N1,j<N2,且word1[i]和word2[j]不同,此时F(i, j)返回以下三个选择中最小的一个
- 1 + F(i + 1, j + 1), 一个替换
- 1 + F(i, j + 1), 一个插入
- 1 + F(i + 1, j), 一个删除
从以上表达式出发,我们使用一个二维的DP数组,以及双重循环,对word1和word2的数组下标分别按从大到小的顺序依次计算DP数组中的各个元素的值,最后DP[0][0]中的数值就是问题的答案。
Java代码如下
class Solution {
public int minDistance(String word1, String word2) {
char[] text1 = word1.toCharArray();
char[] text2 = word2.toCharArray();
int N1 = text1.length;
int N2 = text2.length;
if (N1 == 0) {
return N2;
}
if (N2 == 0) {
return N1;
}
int[][] dp = new int[N1 + 1][N2 + 1];
for(int i = N1; i >=0; i --) {
for(int j = N2; j >=0; j --) {
if (i == N1) {
dp[i][j] = N2 - j;
} else if (j == N2) {
dp[i][j] = N1 - i;
} else {
if (text1[i] == text2[j]) {
dp[i][j] = dp[i + 1][j + 1];
} else {
int min = dp[i + 1][j + 1];
min = Math.min(min, dp[i][j + 1]);
min = Math.min(min, dp[i + 1][j]);
dp[i][j] = min + 1;
}
}
}
}
return dp[0][0];
}
}