583. 两个字符串的删除操作
思路:直接动态规划五步曲。
- dp[i][j]:以i-1为结尾的字符串word1,和以j-1为结尾的字符串word2,想要达到相等,所需要删除元素的最少次数。
- 递推公式分情况讨论
当word1[i - 1] 与 word2[j - 1]相同的时候,dp[i][j]=dp[i - 1][j - 1]
当word1[i - 1] 与 word2[j - 1]不相同的时候,有三种情况,这三种情况要求最小值,因为最后要求最小的操作步数。
- 删除word1[i - 1],此时dp[i][j] = dp[i - ][j] + 1;
- 删除word2[j - 1],此时dp[i][j] = dp[i][j - 1] + 1;
- 同时删word1[i - 1]和word2[j - 1],此时dp[i][j] = dp[i - 1][j - 1] + 2
- 初始化,dp[i][0]代表当word2为空串式,word1要删除的元素个数,很明显,dp[i][0] = i,dp[0][j]也是同理。
- 遍历顺序,由递推公式我们可知道,需要从上到小,从左到右遍历。
- 举例说明
这里使用的代码和思路分析中的代码有所差别,
代码中是将问题转换成了求解的共子序列问题然后来求解。
class Solution {
public int minDistance(String word1, String word2) {
int[][] dp = new int[word1.length() + 1][word2.length() + 1];
char[] arr1 = word1.toCharArray();
char[] arr2 = word2.toCharArray();
for (int i = 1; i <= arr1.length; i++) {
for (int j = 1; j <= arr2.length; j++) {
if (arr1[i - 1] == arr2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return arr1.length + arr2.length - 2 * dp[arr1.length][arr2.length];
}
}
72. 编辑距离
思路:本题是经典的编辑距离问题,使用动规非常巧妙,动态规划五步曲分析:
- dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]。
- 递推公式:分情况讨论
当word1[i - 1] == word2[j - 1],不需要做任何操作,dp[i][j] = dp[i - 1][j - 1]
当word1[i - 1] != word2[j - 1],需要做增删或者替换操作。这三种操作同样要求最小值,因为是求最小编辑距离。
- 删除word1[i - 1],此时dp[i][j] = dp[i - 1][j] + 1
- 删除word2[j - 1],此时dp[i][j] = dp[i][j - 1] + 1(注意这里没有增加操作,因为删除word1就相当于增加word2,删除word2就相当于增加word1,不要重复累计)
- 替换一个元素,此时dp[i][j] = dp[i - 1][j - 1] + 1
- 初始化,本题初始化原理与上一题相同。
- 遍历顺序为从上到下从左到右遍历
- 举例说明
class Solution {
public int minDistance(String word1, String word2) {
// dp[i][j] 表示下标为i-1结尾的word1和下标为j-1结尾的word2的最近编辑距离。
int[][] dp = new int[word1.length() + 1][word2.length() + 1];
char[] arr1 = word1.toCharArray();
char[] arr2 = word2.toCharArray();
for (int i = 0; i <= word1.length(); i++) dp[i][0] = i;
for (int j = 0; j <= word2.length(); j++) dp[0][j] = j;
for (int i = 1; i <= arr1.length; i++) {
for (int j = 1; j <= arr2.length; j++) {
if (arr1[i - 1] == arr2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i - 1][j], dp[i][j - 1])) + 1;
}
}
}
return dp[arr1.length][arr2.length];
}
}
编辑距离总结
从判断子序列开始,都是编辑距离的问题,前三道题目依次递进,为最后编辑距离的问题做了很好的铺垫。