算法设计与分析(九)

712. Mininum ASCII Delete Sum for Two Strings

Given two strings s1, s2, find the lowest ASCII sum of deleted characters to make two strings equal.

Example1

Input: s1 = “sea”, s2 = “eat”
Output: 231
Explanation: Deleting “s” from “sea” adds the ASCII value of “s” (115) to the sum.
Deleting “t” from “eat” adds 116 to the sum.
At the end, both strings are equal, and 115 + 116 = 231 is the minimum sum possible to achieve this.

Example2

Input: s1 = “delete”, s2 = “leet”
Output:403
Explanation: Deleting “dee” from “delete” to turn the string into “let”,
adds 100[d]+101[e]+101[e] to the sum. Deleting “e” from “leet” adds 101[e] to the sum.
At the end, both strings are equal to “let”, and the answer is 100+101+101+101 = 403.
If instead we turned both strings into “lee” or “eet”, we would get answers of 433 or 417, which are higher.

Note

0 < s1.length, s2.length <= 1000.
All elements of each string will have an ASCII value in [97, 122].

思路

这道题在上周就在LeetCode看到了,当时在找动态规划的题目做,看到题目的时候瞬间傻了。这竟然能用动态规划解出来?看着明明很像贪心的题目啊。顺着贪心的思路想了一下,发现情况很复杂,要把情况分类的话一时半会弄不出来,于是放弃了。

刚好这一周老师讲了动态规划的几种常见题型,这道题属于“最小编辑距离”的小变种。课堂上听到“最小编辑距离”题目的解法时,我都惊了,感受就是原来还能这样做?所以这周就尝试着做一下类似的题目,练一下手。

  1. 首先我们定义,对于 n 个字符的字符串str,它的字符顺序为[1..n],不使用常用的[0..n-1]是因为我要用str[0]表示空字符。
  2. 对于两个字符串 s1 和 s2,状态空间的定义如下:
    cost[i][j]表示使s1[1..i]s2[1..j] 相等的代价,即需要删除的字母的ASCII码之和。
    cost[0][j],表示s1是空串,s2为了与s1相等,需要把[1..j]的字母都删除掉。对于j=0的情况也类似处理。
  3. 所以我们可以得出以下状态转移方程:
cost[i][j]=min(cost_i + cost[i-1][j], cost_j + cost[i][j-1], diff + cost[i-1][j-1]);

(1) cost_i + cost[i-1][j]:删除s1[i]后,s1[1..i]s2[1..j]相等。
(2) cost_j+ cost[i][j-1]:删除s2[j]后,s1[1..i]s2[1..j]相等。
(3) diff + cost[i-1][j-1]:如果s1[i]等于s2[j,则不需要删除任何一个字母,代价diff0,否则两个字母都要删除,代价为cost_i+cost_j
4. 还有一点要注意的就是,在开始状态转移方程计算的循环之前,我们要初始化数组:

//初始化代价数组,s1或者s2变成空串需要的代价
for (int i = 1; i <= n; i++)
   cost[i][0] = s1[i - 1] + cost[i - 1][0];
for (int i = 1; i <= m; i++)
   cost[0][i] = s2[i - 1] + cost[0][i - 1];

代码

class Solution {

int min(int num1, int num2, int num3)
{
  if (num1 <= num2 && num1 <= num3) return num1;
  else if (num2 <= num1 && num2 <= num3) return num2;
  else return num3;
}

public:
    int minimumDeleteSum(string s1, string s2) 
    {
        int n = s1.size();
        int m = s2.size();
        int cost[n + 1][m + 1] = {0};
        int cost_i = 0;
        int cost_j = 0;
        int diff = 0;

		//初始化代价数组,s1或者s2变成空串需要的代价
        for (int i = 1; i <= n; i++)
          cost[i][0] = s1[i - 1] + cost[i - 1][0];
        for (int i = 1; i <= m; i++)
          cost[0][i] = s2[i - 1] + cost[0][i - 1];

        for (int i = 1; i <= n; i++)
          for (int j = 1; j <= m; j++)
          {

            cost_i = s1[i - 1];
            cost_j = s2[j - 1];
            //如果两个字母相同则保留,代价为0,否则同时删除,代价为ASCII码的和
            if (s1[i - 1] == s2[j - 1]) diff = 0;	
            else diff = cost_i + cost_j;
            cost[i][j] = min(cost_i + cost[i - 1][j], 		//删除s1的第i个字母
                             cost_j+ cost[i][j - 1],		//删除s2的第j个字母
                             diff + cost[i - 1][j - 1]);	//同时保留或删除两个字母
          }

        return cost[n][m];

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值