编辑距离
题目描述:
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。你可以对一个单词进行如下三种操作:
- 插入一个字符
- 删除一个字符
- 替换一个字符
提示:0 <= word1.length, word2.length <= 500word1 和 word2 由小写英文字母组成
示例
输入:word1 = "intention", word2 = "execution"输出:5解释:intention -> inention (删除 't')inention -> enention (将 'i' 替换为 'e')enention -> exention (将 'n' 替换为 'x')exention -> exection (将 'n' 替换为 'c')exection -> execution (插入 'u')
class Solution {
public int minDistance(String word1, String word2) {
// 初始化
int len1 = word1.length();
int len2 = word2.length();
// 特殊判断
if(len1 == 0 && len2 == 0){
return 0;
}else if(len1 == 0 && len2 != 0){
return len2;
}else if(len1 != 0 && len2 == 0){
return len1;
}
int[][] dp = new int[len1][len2];
boolean flag = false; // 查重标记
if(word1.charAt(0) == word2.charAt(0)) dp[0][0] = 0;
else{
dp[0][0] = 1;
flag = true;
};
flag = false;
for(int i = 1 ; i<len2 ; i++){
// 由word1的第一个单词变为word2的前i+1个单词
if(flag || word1.charAt(0) != word2.charAt(i)) dp[0][i] = dp[0][i-1]+1;
else{
flag = true;
dp[0][i] = dp[0][i-1];
}
}
flag = false;
for(int i = 1 ; i<len1 ; i++){
// 由word1的前i+1个单词变为word2的第一个单词
if(flag || word1.charAt(i) != word2.charAt(0)) dp[i][0] = dp[i-1][0]+1;
else{
flag = true;
dp[i][0] = dp[i-1][0];
}
}
// 动态规划过程
for(int i = 1 ; i<len1 ; i++){
for(int j = 1 ; j<len2 ; j++){
int temp1 = dp[i-1][j-1]+(word1.charAt(i) == word2.charAt(j)?0:1); // 替换操作
int temp2 = dp[i][j-1]+1; // 插入操作
int temp3 = dp[i-1][j]+1; // 删除操作
dp[i][j] = (temp1>temp2?temp2:(temp1>temp3?temp3:temp1)); // 将最小的操作步数赋值给dp[i][j]
}
}
return dp[len1-1][len2-1];
}
}
动态规划题目,定义存储数组为dp[i][j]为word1前i+1个单词转变到word2前j+1个单词的最少操作数。
考虑边界条件:i == 0:即word1的第一个单词转换为word2的前j个单词的操作数这里有两种情况:一种是word2的前j个单词包括了word1的第一个单词 dp[0][j] = j-1另一种是没有包括 dp[0][j] = j;由对称性可知:j == 0:同样有两种情况:一种是word2的前j个单词包括了word1的第一个单词 dp[i][0] = i-1另一种是没有包括 dp[i][0] = i;其次考虑非边界条件:由于只有三种操作,故分三种情况讨论:
- 替换操作:temp1 = dp[i-1][j-1] + (word1[i]==word2[j]?0:1);
- 插入操作:temp2 = dp[i][j-1] + 1;
- 删除操作:temp3 = dp[i-1][j] + 1;
- 最终求:dp[i][j] = min(temp1,temp2,temp3);