【力扣】 两个字符串的最小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 由小写英文字母组成

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

关于最长公共子序列问题,可以参考下面博客:

【力扣】最长公共子序列-CSDN博客
1、状态表示
dpij 表示: s1 的 0, i 区间以及 s2 的 0, j 区间内的所有的子序列中,公 共子序列的 ASCII 最大和 。
2、状态转移方程
对于 dpij 根据最后一个位置的元素,结合题目要求,分情况讨论:
(1)当 s1i == s2j 时:应该先在 s1 的 0, i - 1 区间以及 s2 的 0, j - 1 区间内找一个公共子序列的 ASCII 最大和,然后在它们后面加上一个 s1i 字符即可。
此时 dpij = dpi - 1j - 1 + s1i
(2)当 s1i != s2j 时:公共子序列的ASCII最大和会有三种可能:

  • s1 的 0, i - 1 区间以及 s2 的 0, j 区间内:此时 dpij = dpi - 1j
  • s1 的 0, i 区间以及 s2 的 0, j - 1 区间内:此时 dpij = dpij - 1
  • s1 的 0, i - 1 区间以及 s2 的 0, j - 1 区间内:此时 dpij = dpi - 1j - 1

但是前两种情况里面包含了第三种情况,因此仅需考虑前两种情况下的最大值即可。
综上所述,状态转移方程为:
当 s1i - 1 == s2j - 1 时, dpij = dpi - 1j - 1 + s1i
当 s1i - 1 != s2j - 1 时, dpij = max(dpi - 1j, dpij - 1)
3、初始化
我们将原始 dp 表的规模多加上一行和一列,表示空串。 引入空串后,大大的方便了初始化。
但要 注意下标的映射关系 ,以及里面的值要保证后续填表是正确的。
当 s1 为空时,没有长度,同理 s2 也是。因此第一行和第一列里面的值初始化为 0,即可保证
后续填表是正确的。
4、填表顺序
从上往下填每一行,每一行从左往右。
5、返回值
(1)先找到 dpmn ,也是最大公共 ASCII 和;(2)统计两个字符串的 ASCII 码和 sum; (3)返回 sum - 2 * dpmn

三、代码

java 复制代码
public int minimumDeleteSum(String s1, String s2) {
        int m = s1.length();
        int n = s2.length();
        int[][] dp = new int[m+1][n+1];
        for(int i = 1; i <= m; i++) {
            for(int j = 1; j <= n; j++) {
                if(s1.charAt(i-1) == s2.charAt(j-1)) {
                    dp[i][j] = dp[i-1][j-1] + s1.charAt(i-1);
                }else {
                    dp[i][j] = Math.max(dp[i][j-1], dp[i-1][j]);
                }
            }
        }
        int sum = 0;
        for(char ch : s1.toCharArray()) {
            sum += ch;
        }
        for(char ch : s2.toCharArray()) {
            sum += ch;
        }
        return sum - dp[m][n] - dp[m][n];
    }
相关推荐
我命由我1234517 分钟前
Android 开发问题:MlKitException: An internal error occurred during initialization.
android·java·java-ee·android jetpack·android-studio·androidx·android runtime
CS创新实验室25 分钟前
从顺序表到动态数组:数据结构的永恒基石与现代语言的优雅封装
数据结构·算法
888CC++32 分钟前
java 并发编程
java·开发语言·python
无风听海1 小时前
JSON Web Token(JWT)完全指南
java·前端·json
Black蜡笔小新1 小时前
自动化AI算法训练服务器DLTM训推一体化平台助力农业生产管理实现安全智能化
人工智能·算法·自动化
JAVA社区2 小时前
Java高级全套教程(十一)—— Kubernetes 超详细企业级实战详解
java·运维·微服务·容器·面试·kubernetes
8Qi82 小时前
LeetCode 23. 合并 K 个升序链表 —— 小顶堆(PriorityQueue)
数据结构·算法·leetcode·链表·
QiLinkOS2 小时前
《打破“用爱发电”:一种基于 Gitee 与时间戳的开源权益分配机制探索》
c语言·数据结构·c++·科技·算法·gitee·开源
松间听晚3 小时前
Agentic RL 环境和代码学习:以HGPO为例
算法
智者知已应修善业3 小时前
【51单片机用T0定时器方式1,实现0.5S的时间间隔实现第一次一个灯亮、第二次二个灯亮,直到全部灯亮,然后重复整个过程】2023-12-29
c++·经验分享·笔记·算法·51单片机