每日OJ题_两个数组dp⑦_力扣712. 两个字符串的最小ASCII删除和

目录

[力扣712. 两个字符串的最小ASCII删除和](#力扣712. 两个字符串的最小ASCII删除和)

解析代码


力扣712. 两个字符串的最小ASCII删除和

712. 两个字符串的最小ASCII删除和

难度 中等

给定两个字符串s1s2,返回 使两个字符串相等所需删除字符的 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
  • s1s2 由小写英文字母组成
cpp 复制代码
class Solution {
public:
    int minimumDeleteSum(string s1, string s2) {

    }
};

解析代码

正难则反: 求两个字符串的最小 ASCII 删除和,其实就是找到两个字符串中所有的公共子序列里面, ASCII 最大和。 因此思路就是按照最长公共子序列的分析方式来分析。

**状态表示:**对于两个字符串之间的 dp 问题,一般的思考方式如下:

选取第一个字符串的 [0, i] 区间以及第二个字符串的 [0, j] 区间当成研究对象,结合题目的要求来定义状态表示。然后根据两个区间上最后一个位置的字符 ,来进行分类讨论,从而确定状态转移方程。

dp[i][j] 表示 s1 的 [0, i] 区间以及 s2 的 [0, j] 区间内的所有的子序列中,公共子序列的 ASCII 最大和。


状态转移方程:

对于 dp[i][j] 根据最后一个位置的字符,结合题目要求,来进行分类讨论:

  • 当 s1[i] == s2[j] 时 :应该先在 s1 的 [0, i - 1] 区间以及 s2 的 [0, j - 1] 区间内找一个公共子序列的最大和,然后在它们后面加上一个 s1[i]字符即可。 此时dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + s1[i]);
  • 当 s1[i] != s2[j] 时:公共子序列的最大和会有三种可能:
  1. s1 的 [0, i - 1] 区间以及 s2 的 [0, j] 区间内:此时 dp[i][j] = dp[i - 1][j] ;
  2. s1 的 [0, i] 区间以及 s2 的 [0, j - 1] 区间内:此时 dp[i][j] = dp[i][j - 1] ;
  3. s1 的 [0, i - 1] 区间以及 s2 的 [0, j - 1] 区间内:此时 dp[i][j] = dp[i - 1][j - 1] ;

但是前两种情况里面包含了第三种情况,因此仅需考虑前两种情况下的最大值即可。

综上所述,状态转移方程为:

  • 当 s1[i - 1] == s2[j - 1] 时, dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + s1[i]);
  • 当 s1[i - 1] != s2[j - 1] 时, dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) ;

**初始化:**空串是有研究意义的,因此我们将原始 dp 表的规模多加上一行和一列,表示空串。当 s1 为空时,没有长度,同理 s2 也是。因此第一行和第一列里面的值初始化为 0 即可保证后续填表是正确的。

填表顺序:从上往下填写每一行,每一行从左往右。

返回值:找到dp[m][n], ,也是最大公共 ASCII 和,然后统计两个字符串的 ASCII 码和 sum,最后返回sum - 2 * dp[m][n]

cpp 复制代码
class Solution {
public:
    int minimumDeleteSum(string s1, string s2) {
        int sum = 0;
        for(auto& e : s1)
            sum += e;
        for(auto& e : s2)
            sum += e;
        int m = s1.size(), n = s2.size();
        s1 = " " + s1, s2 = " " + s2;
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
        // dp[i][j]表示s1的[0, i]区间以及s2的[0, j]区间内的所有的子序列中,
        // 公共子序列的 ASCII 最大和。
        for(int i = 1; i <= m; ++i)
        {
            for(int j = 1; j <= n; ++j)
            {
                if(s1[i] == s2[j])
                    dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + s1[i]);
                else // ((s1[i] != s2[j]))
                    dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
            }
        }
        return sum - 2 * dp[m][n];
    }
};

​​​​​​​

相关推荐
工业3D_大熊43 分钟前
3D可视化引擎HOOPS Luminate场景图详解:形状的创建、销毁与管理
java·c++·3d·docker·c#·制造·数据可视化
暮色_年华1 小时前
Modern Effective C++ Item 11:优先考虑使用deleted函数而非使用未定义的私有声明
c++
流星白龙1 小时前
【C++习题】10.反转字符串中的单词 lll
开发语言·c++
Smile丶凉轩1 小时前
微服务即时通讯系统的实现(服务端)----(1)
c++·git·微服务·github
肥猪猪爸2 小时前
使用卡尔曼滤波器估计pybullet中的机器人位置
数据结构·人工智能·python·算法·机器人·卡尔曼滤波·pybullet
readmancynn2 小时前
二分基本实现
数据结构·算法
萝卜兽编程2 小时前
优先级队列
c++·算法
盼海2 小时前
排序算法(四)--快速排序
数据结构·算法·排序算法
一直学习永不止步2 小时前
LeetCode题练习与总结:最长回文串--409
java·数据结构·算法·leetcode·字符串·贪心·哈希表
Rstln3 小时前
【DP】个人练习-Leetcode-2019. The Score of Students Solving Math Expression
算法·leetcode·职场和发展