题目链接:
712. 两个字符串的最小ASCII删除和 - 力扣(LeetCode)leetcode-cn.com题目描述:
给定两个字符串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 的结果,比答案更大。
注意:
0 < s1.length, s2.length <= 1000
。- 所有字符串中的字符ASCII值在
[97, 122]
之间。
解题思路:
本题和两个字符串的删除操作有点类似,但是那一题是要求使两个字符串相同所需的最小步数,本题则是要求使两个字符串相等所需删除字符的ASCII值的最小和。
但是总的思路还是相似的,都是用动态规划。假设 s1.length=n,s2.length=m,我们用 dp[i][j] 表示字符串 s1[:i] 和 s2[:j](s1[:i] 表示字符串 s1 从开头到第 i-1 位的子串,s2[:j] 表示字符串 s2 从开头到第 j-1 位的子串)达到相等所需删除的字符的 ASCII 值的最小和,最终的答案为 dp[n][m]。
首先确定一下边界条件,当 s1[:i] 和 s2[:j] 中的某一个字符串为空时,dp[i][j] 的值即为另一个非空字符串的所有字符的 ASCII 值之和。
dp[i][0] = dp[i-1][0] + ascii(s1[i-1])
对于其余的一般情况,即两个字符串都非空时,如果有 s1[i] == s2[j],那么当前位置的两个字符相同,它们不需要被删除,状态转移方程为
dp[i][j] = dp[i-1][j-1]
如果 s1[i] != s2[j],那么我们至少要删除 s1[i] 和 s2[j] 两个字符中的一个,因此状态转移方程为
dp[i][j]=min(dp[i-1][j]+ascii(s1[i-1]), dp[i][j-1]+ascii(s2[j-1]))
有了这些,写代码就很容易了。
代码如下:
class Solution {
public:
int minimumDeleteSum(string s1, string s2) {
int n = s1.size(), m = s2.size();
vector<vector<int>> dp(n+1, vector<int>(m+1, 0));
for (int i = 1; i <= n; ++i) {
dp[i][0] = dp[i-1][0] + ascii(s1[i-1]);
}
for (int i = 1; i <= m; ++i) {
dp[0][i] = dp[0][i-1] + ascii(s2[i-1]);
}
for (int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++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]+ascii(s1[i-1]), dp[i][j-1]+ascii(s2[j-1]));
}
}
}
return dp[n][m];
}
private:
int ascii(char c){
return c - 'a' + 97;
}
};
如果有任何疑问,欢迎提出。如果有更好的解法,也欢迎告知。