代码随想录算法训练营day56 | 583. 两个字符串的删除操作,72. 编辑距离,编辑距离总结篇
- 583. 两个字符串的删除操作
- 解法一:动态规划
- 解法二:计算最长公共子序列,然后用数组长度减掉子序列长度
- 72. 编辑距离
- 解法一:动态规划
- 编辑距离总结篇
583. 两个字符串的删除操作
教程视频:https://www.bilibili.com/video/BV1we4y157wB
解法一:动态规划
思路:
1、dp[i][j]定义:以索引i-1结尾的word1和以j-1结尾的word2相同所需要的最小步数
2、递推公式:
if(word1.charAt(i-1)==word2.charAt(j-1)){
dp[i][j]=dp[i-1][j-1];
}else{
dp[i][j]=Math.min(dp[i-1][j], dp[i][j-1])+1;
}
3、初始化dp:索引包含0表示空串,dp[i][0]=i; dp[0][j]=j;
4、 遍历顺序:两层for均正向遍历
5、打印验证
class Solution {
public int minDistance(String word1, String word2) {
// 1. dp[i][j]定义:以索引i-1结尾的word1和以j-1结尾的word2相同所需要的最小步数
int[][] dp = new int[word1.length()+1][word2.length()+1];
// 3. 初始化dp:索引包含0表示空串,dp[i][0]=i; dp[0][j]=j;
for(int i=1;i<=word1.length();i++){
dp[i][0]=i;
}
for(int j=1;j<=word2.length();j++){
dp[0][j]=j;
}
// 4. 遍历顺序:两层for均正向遍历
for(int i=1;i<=word1.length();i++){
for(int j=1;j<=word2.length();j++){
// 2. 递推公式:
if(word1.charAt(i-1)==word2.charAt(j-1)){
dp[i][j]=dp[i-1][j-1];
}else{
// 这里简化了dp[i-1][j-1]+2
dp[i][j]=Math.min(dp[i-1][j], dp[i][j-1])+1;
}
}
}
// 5. 打印验证
return dp[word1.length()][word2.length()];
}
}
解法二:计算最长公共子序列,然后用数组长度减掉子序列长度
结果为word1.length()+word2.length()-2*childLength
最长公共子序列代码见:https://editor.csdn.net/md/?articleId=130897102
72. 编辑距离
教程视频:https://www.bilibili.com/video/BV1qv4y1q78f
解法一:动态规划
思路:
1、dp[i][j]定义:以索引i-1结尾的word1和以j-1结尾的word2相同所需要的最少操作次数
2、递推公式:
if(word1.charAt(i-1)==word2.charAt(j-1)){
dp[i][j]=dp[i-1][j-1];
}else{
dp[i][j]= Math.min(dp[i-1][j-1]+1, Math.min(dp[i-1][j]+1, dp[i][j-1]+1));
}
3、初始化dp:索引包含0表示空串,dp[i][0]=i; dp[0][j]=j;
4、 遍历顺序:两层for均正向遍历
5、打印验证
class Solution {
public int minDistance(String word1, String word2) {
int[][] dp =new int[word1.length()+1][word2.length()+1];
for(int i=1;i<=word1.length();i++){
dp[i][0]=i;
}
for(int j=1;j<=word2.length();j++){
dp[0][j]=j;
}
for(int i=1;i<=word1.length();i++){
for(int j=1;j<=word2.length();j++){
if(word1.charAt(i-1)==word2.charAt(j-1)){
dp[i][j]=dp[i-1][j-1];
}else{
// 替换操作dp[i-1][j-1]+1
// 增加和删除互为逆向操作,逻辑一样,金考虑删除即可Math.min(dp[i-1][j]+1, dp[i][j-1]+1)
dp[i][j]= Math.min(dp[i-1][j-1]+1, Math.min(dp[i-1][j]+1, dp[i][j-1]+1));
}
}
}
return dp[word1.length()][word2.length()];
}
}
编辑距离总结篇
教程:动态规划之编辑距离总结篇
结合我的笔记:
代码随想录算法训练营day52 | 300.最长递增子序列,674. 最长连续递增序列,718. 最长重复子数组
代码随想录算法训练营day53 | 1143.最长公共子序列,1035.不相交的线,53. 最大子序和 动态规划
代码随想录算法训练营day55 | 392.判断子序列,115.不同的子序列
- 判断子序列只需要计算删除的情况,不用考虑增加和替换的情况,递推公式为:
if (s[i - 1] == t[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
else dp[i][j] = dp[i][j - 1];
- 不同的子序列虽然也只有删除操作,不用考虑替换增加之类的,但可以重复匹配,递推公式变为:
if (s[i - 1] == t[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
} else {
dp[i][j] = dp[i - 1][j];
}
- 两个字符串的删除操作。
当word1[i - 1] 与 word2[j - 1]相同的时候,dp[i][j] = dp[i - 1][j - 1];
当word1[i - 1] 与 word2[j - 1]不相同的时候,dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1});
if (word1[i - 1] == word2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = Math.min(dp[i - 1][j - 1] + 2, Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1));
}
- 编辑距离
word2添加一个元素,相当于word1删除一个元素,由此可见增加和删除互为逆向操作,word2添加一个元素d,也就是相当于word1删除一个元素d,操作数是一样!所以递推公式为:
if (word1[i - 1] == word2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
}else {
dp[i][j] = Math.min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;
}