712. 两个字符串的最小ASCII删除和
给定两个字符串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 的结果,比答案更大。
.............................................................................................................................................................
思路
- 当字符串s1的第i个字符与字符串s2的第j个字符相同时,最小和f( i ,j ) 等同于s1的前i-1个字符与s2的前j-1个字符的最小和 f( i-1, j-1).
F ( i , j ) = F ( i − 1 , j − 1 ) , s 1 [ i ] = = s 2 [ j ] F(i,j) = F(i-1,j-1) , \quad\quad\quad s1[i] == s2[j] F(i,j)=F(i−1,j−1),s1[i]==s2[j]
2.当字符串s1的第i个字符与字符串s2的第j个字符不相同时,有两种操作:
-
通过在s1末尾删除第i个字符,此时使用s1的第i-1个字符与s2的第j个字符比较,最小和等同于s1的前i个字符与s2的前j-1个字符的操作数 f( i-1, j) + s1(i).
-
通过在s2末尾删除第j个字符,此时使用s1的第i个字符与s2的第j-1个字符比较,最小和等同于s1的前i-1个字符与s2的前j个字符的操作数 f( i, j-1) + s2(j).
此时最小和等于以上两种操作中最小的最小和
F
(
i
,
j
)
=
m
i
n
{
F
(
i
−
1
,
j
)
+
s
1
(
i
)
,
删除
s
1
的第
i
个字符
F
(
i
,
j
−
1
)
+
s
2
(
j
)
,
删除
s
2
的第
j
个字符
F(i,j) = min \begin{cases} F(i-1,j)+s1(i) , \quad\quad\quad\quad\quad 删除s1的第i个字符\\ F(i,j-1)+s2(j),\quad\quad\quad\quad\quad 删除s2的第j个字符\\ \end{cases}
F(i,j)=min{F(i−1,j)+s1(i),删除s1的第i个字符F(i,j−1)+s2(j),删除s2的第j个字符
C++ 代码:
int minimumDeleteSum(string s1, string s2) {
int n = s1.size();
int m = s2.size();
vector<vector<int>> dp(m+1, vector<int>(n+1, 0));
//初始化
for (int i = 1; i <= m; i++)
dp[i][0] = dp[i - 1][0] + s2[i - 1];
for (int j = 1; j <= n; j++)
dp[0][j] = dp[0][j-1] + s1[j - 1];
//dp填表
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= n; j++)
{
if (s1[j - 1] == s2[i - 1])
dp[i][j] = dp[i - 1][j - 1];
else
dp[i][j] = (dp[i][j - 1] + s1[j - 1]) < (dp[i - 1][j] + s2[i - 1]) ?
(dp[i][j - 1] + s1[j - 1]) : (dp[i - 1][j] + s2[i - 1]);
}
}
return dp[m][n];
}