leetcode72.编辑距离
题目:
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
- 插入一个字符
- 删除一个字符
- 替换一个字符
提示:
- 和 由小写英文字母组成
思路:
使用动态规划:状态表示表示将变成所需要的最少操作次数。因为分别有插入、删除、修改三种操作方式。所以共有三种状态转移方程:
- 插入一个字符变成:
- 删除一个字符变成:
- 替换一个字符变成:
代码(Java):
class Solution {
public int minDistance(String w1, String w2) {
w1 = " " + w1;
w2 = " " + w2;
int n = w1.length(),m = w2.length();
int[][] f = new int[n+1][m+1];
for(int i = 0;i <= n;i++)
f[i][0] = i;
for(int i = 0;i <= m;i++)
f[0][i] = i;
for(int i = 1;i <= n;i++) {
for(int j = 1;j <= m;j++) {
f[i][j] = Math.min(f[i][j-1],f[i-1][j]) + 1;
f[i][j] = Math.min(f[i][j],f[i-1][j-1] + (w1.charAt(i-1) == w2.charAt(j-1) ? 0 : 1));
}
}
return f[n][m];
}
}
编辑距离变形题(简化):leetcode583.两个字符串的删除操作
题目
给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。
提示:
- 给定单词的长度不超过500。
- 给定单词中的字符只含有小写字母。
思路:
解法1:当作是编辑距离的简化版。这里是只有删除操作,将变成有两种操作:一是删除变成,那么;二是删除变成,那么。另外还有特殊情况,就是,那么。
代码(Java):
class Solution {
public int minDistance(String w1, String w2) {
int n = w1.length(), m = w2.length();
w1 = " " + w1;
w2 = " " + w2;
int[][] f = new int[n+1][m+1];
for(int i = 0;i <= n;i++) {
f[i][0] = i;
}
for(int j = 0;j <= m;j++) {
f[0][j] = j;
}
for(int i = 1;i <= n;i++) {
for(int j = 1;j <= m;j++) {
f[i][j] = Math.min(f[i-1][j],f[i][j-1]) + 1;
if(w1.charAt(i) == w2.charAt(j)) {
f[i][j] = Math.min(f[i][j],f[i-1][j-1]);
}
}
}
return f[n][m];
}
}
解法2:这题是对两个字符串分别删除一些元素使得两个字符串相同,所以可以联想到两个字符串的最长公共子序列问题。求出两个字符串的最长公共子序列的长度k,那么这题的解就是
class Solution {
public int minDistance(String w1, String w2) {
int n = w1.length(),m = w2.length();
w1 = " " + w1;
w2 = " " + w2;
int[][] f = new int[n+1][m+1];
for(int i = 1;i <= n;i++) {
for(int j = 1;j <= m;j++) {
f[i][j] = Math.max(f[i-1][j],f[i][j-1]);
if(w1.charAt(i) == w2.charAt(j)) {
f[i][j] = Math.max(f[i][j],f[i-1][j-1] + 1);
}
}
}
return n + m - 2 * f[n][m];
}
}