题目来源
题目描述
class Solution {
public:
int minimumDeleteSum(string s1, string s2) {
}
};
题目解析
分析
- 将各个字母转换成ASCII码值,求出最大相同的ASCII值之和,就相当于求最长公共子序列
思路:最长公共子序列
- 定义dp[i][j]:
- 只考虑字符串str1的前i个字符和字符串s2的前j个字符变得相等时所要删除的字符的最小ASCII值
- 最终返回dp[N1][N2]
- 初始化:
- 什么是边界呢?当有一个字符串为空时,另一个字符串由多少字符就要删除多少字符。所以
- dp[0][j]:一直累加str2[j]
- dp[i][0]:一直累加str1[i]
- 什么是边界呢?当有一个字符串为空时,另一个字符串由多少字符就要删除多少字符。所以
- 状态转移方程:
- 当str1[i - 1] == str2[j - 1]时,不需要删除,所以直接令dp[i][j] = dp[i - 1][j - 1]
- 当str1[i - 1] != srr2[j - 1]时,那么有两种情况:
- 可以删除str1[i - 1]的字符,此时dp[i][j] = dp[i - 1][j] + str1[i - 1]
- 或者删除str2[j - 1]的字符,此时dp[i][j] = dp[i][j - 1] + str2[j - 1]
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 j = 1; j <= n; ++j)
dp[0][j] = dp[0][j - 1] + s2[j - 1];
for (int i = 1; i <= m; ++i) {
dp[i][0] = dp[i - 1][0] + s1[i - 1];
for (int j = 1; j <= n; ++j) {
dp[i][j] = (s1[i - 1] == s2[j - 1]) ? dp[i - 1][j - 1] : min(dp[i - 1][j] + s1[i - 1], dp[i][j - 1] + s2[j - 1]);
}
}
return dp[m][n];
}
};
思路
还可以先计算s1和s2的最大相同子序列的ASCII码值,然后用s1和s2的所有字符之和减去这个最大的ASCII码值的两倍
- dp[i][j]: 字符串s1的前i个字符和s2的前j个字符的最大相同子序列的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; ++i) {
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]);
}
}
int sum1 = accumulate(s1.begin(), s1.end(), 0);
int sum2 = accumulate(s2.begin(), s2.end(), 0);
return sum1 + sum2 - 2 * dp[m][n];
}
};