583. 两个字符串的删除操作 - 力扣(LeetCode)
相当于这一题的简化版:
LeetCode第 72 题:编辑距离(C++)_zj-优快云博客
动态规划
考虑目前正在处理第 i-1, j-1 个位置(之前的已经处理好),转移状态方程:
if(word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1];//相等的时候我们什么不做,删除次数不变
else 需要进行一步删除操作,可以删除word1的i-1字符或者word2中的j-1字符,至于删除那个好,取决于
dp[i-1][j]和dp[i][j-1]那个小,所以:
dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1]);//+1 是因为进行了一步删除
反过来想,我们是如何走到(i, j)这个状态的,有三种可能:
- (i-1, j-1)匹配,那就直接++i, ++j进入(i, j)状态
- (i-1, j)不匹配,我们删除word1[i-1],考虑下一个状态(i, j)
- (i, j-1)不匹配,我们删除word2[j-1],考虑下一个状态(i, j)
这儿的删除并不是真正意义上的删除,只是将下标右移,去考虑下一个字符。
初始dp代码:
class Solution {
public:
int minDistance(string word1, string word2) {
int m = word1.size(), n = word2.size();
vector<vector<int>> dp(m+1, vector<int>(n+1, 0));
for(int i = 1; i < n+1; ++i) dp[0][i] = dp[0][i-1] + 1;//第0行
for(int i = 1; i < m+1; ++i) dp[i][0] = dp[i-1][0] + 1;//第0列
for(int i = 1; i < m+1; ++i){
for(int j = 1; j < n + 1; ++j){
if(word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1];
else dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1]);
}
}
return dp[m][n];
}
};
另外常见套路还可以进行空间优化,采用一维数组即可,类似LeetCode第 1143 题:最长公共子序列(C++)_zj-优快云博客的操作,不过会使代码更加难懂。
记忆化递归
自下而上递归,使用二维数组计数避免重复计算
class Solution {
public:
vector<vector<int>> memo;
int dp(string &s1, string& s2, int i, int j){
if(i < 0) return j+1;
if(j < 0) return i + 1;
if(memo[i+1][j+1] != -1) return memo[i+1][j+1];
if(s1[i] == s2[j]){
memo[i+1][j+1] = memo[i][j];
return dp(s1, s2, i-1, j-1); //什么都不做
}
else{
memo[i+1][j+1] = 1 + min(dp(s1, s2, i, j-1), dp(s1, s2, i-1, j));
return memo[i+1][j+1];
}
}
int minDistance(string word1, string word2) {
int m = word1.size(), n = word2.size();
memo = vector<vector<int>>(m+1, vector<int>(n+1, -1));
return dp(word1, word2, m-1, n-1);//从后往前
}
};
转化为最长公共子序列问题
LeetCode第 1143 题:最长公共子序列(C++)_zj-优快云博客
解释:
两个字符串的删除操作 - 两个字符串的删除操作 - 力扣(LeetCode)
过程就是:
(1) 先获取最长公共子序列,
(2)之后s1.length() + s2.length() - 2 * 最长公共子序列长度。
class Solution {
public:
int minDistance(string word1, string word2) {
int m = word1.size(), n = word2.size();
vector<vector<int>> dp(m+1, vector<int>(n+1, 0));
for(int i = 1; i < m+1; ++i){
for(int j = 1; j < n + 1; ++j){
if(word1[i-1] == word2[j-1]) dp[i][j] = 1 + dp[i-1][j-1];
else dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
return m+n - 2*dp[m][n];
}
};