712. 两个字符串的最小ASCII删除和 - 力扣(LeetCode)
算是这一题LeetCode第 583 题:两个字符串的删除操作(C++)_zj-CSDN博客的进阶,这儿的目的不是使删除步数最小,而是使删除字符的ascii值最小。
动态规划
稍微修改一下状态就可以
dp[i][j]表示处理到s1中的i位字符和s2中的j位字符时,已经删除的字符的ascii码值的最小和,考虑目前正在处理第 i-1, j-1 个位置(之前的已经处理好),转移状态方程:
if(word1[i] == word2[j]) dp[i][j] = dp[i-1][j-1];//相等的时候我们什么不做
else 需要进行一次删除操作,可以删除word1的i-1字符或者word2中的j-1字符,至于删除那个好,取决于
删除哪个之后的ascii和值小,所以:
dp[i][j] = min(dp[i-1][j] + s1[i-1], dp[i][j-1] + s2[j-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)
和583题如出一辙
class Solution {
public:
int minimumDeleteSum(string s1, string s2) {
int m = s1.size(), n = s2.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] + s2[i-1];//第0行
for(int i = 1; i < m+1; ++i) dp[i][0] = dp[i-1][0] + s1[i-1];//第0列
for(int i = 1; i < m+1; ++i){
for(int j = 1; j < n + 1; ++j){
if(s1[i-1] == s2[j-1]) dp[i][j] = dp[i-1][j-1];
else dp[i][j] = min(dp[i-1][j] + s1[i-1], dp[i][j-1] + s2[j-1]);
}
//for(auto c : dp[i]) cout << c << " ";
//cout << endl;
}
return dp[m][n];
}
};
当然也类似583题,转化为最长公共子串问题(要求这些子串的ascii最大):
class Solution {
public:
int minimumDeleteSum(string s1, string s2) {
int m = s1.size(), n = s2.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(s1[i-1] == s2[j-1]) dp[i][j] = s1[i-1] + dp[i-1][j-1];//这儿相等的+s1[i-1]和+s2[j-1]都可以
else dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
int sum=accumulate(s1.begin(), s1.end(), 0);
sum=accumulate(s2.begin(), s2.end(), sum);
return sum - 2*dp[m][n];
}
};