力扣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 的结果,比答案更大。

动态规划解法:

求两个字符串删除若干字符使其相等后删除掉的字符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];
    }
};

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值