题目
给定两个字符串s1
和 s2
,返回 使两个字符串相等所需删除字符的 ASCII 值的最小和 。
示例1:
输入: s1 = "sea", s2 = "eat" 输出: 231 解释: 在 "sea" 中删除 "s" 并将 "s" 的值(115)加入总和。 在 "eat" 中删除 "t" 并将 116 加入总和。 结束时,两个字符串相等,115 + 116 = 231 就是符合条件的最小和。
示例2:
输入: s1 = "delete", s2 = "leet" 输出: 403 解释: 在 "delete" 中删除 "dee" 字符串变成 "let", 将 100[d]+101[e]+101[e] 加入总和。在 "leet" 中删除 "e" 将 101[e] 加入总和。 结束时,两个字符串都等于 "let",结果即为 100+101+101+101 = 403 。 如果改为将两个字符串转换为 "lee" 或 "eet",我们会得到 433 或 417 的结果,比答案更大。
动态规划解法:
求两个字符串删除若干字符使其相等后删除掉的字符ascii码相加之和最小,由于两个字符串的总ascii码之和不变,所以可以反过来求两个字符串最大相同子序列ascii码值之和,再由总和与之相减即可。用a表示删除掉的字符的ascii码之和,b表示剩余字符的ascii码之和,sum表示两个字符串总的ascii码之和,则sum = a + b。若要a最小,则b最大。
我们把问题改为求两个字符串的最大相同子序列。
创建二维数组dp[i][j],表示 s1 的前 i 个字符 和 s2 的前 j 个字符中相同子序列的最大值。
①当 s1[i-1] == s2[j-1](注意 i 和 j 表示的是前i个前j个) 时dp[i][j] = dp[i-1][j-1] + s1[i-1];
②反之 dp[i][j] = max(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]);
由此看出dp[i][j]的值由其左方、上方、左上方的dp值决定,所以我们从左往右、自上而下的遍历dp数组,而从这个顺序来看当s1[i-1] != s2[j-1] 时对于dp[i][j],dp[i-1][j] 和 dp[i][j-1] 一定与 dp[i-1][j-1]比较过了,也就是前两者一定大于等于后者,所以我在代码中只比较了dp[i-1][j] 和 dp[i][j-1]。
C++ 代码如下
class Solution {
public:
int minimumDeleteSum(string s1, string s2) {
int m = s1.size();
int n = s2.size();
vector<vector<int>>dp (m + 1, vector<int>(n + 1, 0));
int sum = 0;
for(int i = 1; i <= m; ++i){
sum += s1[i-1]; //s1的和
for(int j = 1; j <= n; ++j)
if(s1[i-1] == s2[j-1])
dp[i][j] = dp[i-1][j-1] + s1[i-1];
else
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
for(int i = 0; i <n; ++i)
sum += s2[i];//s1+s2的和
return sum - 2*dp[m][n];
}
};