Minimum ASCII Delete Sum for Two Strings 两个字符串的最小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 的结果,比答案更大。

注意:

  • 0 < s1.length, s2.length <= 1000
  • 所有字符串中的字符ASCII值在[97, 122]之间。

思路:这道题是DTW(动态时间规整)的题目,动态时间规整是为了解决两端序列长度不一致而求两端序列相似度的问题,如下图所示:


由于红色线相对于黑线往左偏移,如果直接用欧式距离表征差异性会得到很大的差异,但是其实两端序列是很相似的,所以我们需要一种方法来表征这种长度不一致求相似性的问题,就是动态时间规整。

动态时间规整通过维护一个二维数组dp来记录当前距离差,其中dp[i][j]表示A序列的第i个下标和B序列第j个下标的距离差,假设A序列有m个值,B序列有n个值,那么最后迭代的dp[m][n]就是我们得到的A和B序列的距离差,值越小表示越相似,递推方程模板如下:


其中,累积距离dist(i,j)为当前格点的距离d(A(i),B(j)),也就是两个序列A,B中的对应两点A(i)和B(j)的欧式距离与到达该点的最小的邻近元素的累积距离(dist(i-1,j-1),dist(i-1,j),dist(i,j-1))之和。那么我们来看针对这道问题如何求解呢?

像01背包那样理解即:
s1[0:i] s2[0:j] 中一共有i + j个字符,从s1中从左至右选取若干字符,s2中从左至右选取若干相同字符。那么,那些未被选中的就是要删除的。再换个角度思考即:选取要删除的字符。

DP[i][j] 表示从s1 0-i, s2 0-j 中删除若干字符后,两个字符串相等时,删除的字符串的ASCII值的和的最小值。

那么一个O(mn)的循环扫描中,假设我们已知了DP[i-1][j-1] = a; DP[i-1][j] = b; DP[i][j-1] = c

  • s1[i] == s2[j]时:
    DP[i][j] = DP[i-1][j-1] 因为不需要再删除字符,保留s1[i],s2[j]即可。
  • s1[i] != s2[j]时:
    此时,需要删除字符才能满足相等。
    1)删除s1[i]
    DP[i][j] = DP[i-1][j] + s1[i]
    2)删除s2[j]
    DP[i][j] = DP[i][j-1] + s2[j]
    3)删除s1[i]s2[j]
    DP[i][j] = DP[i-1][j-1] + s1[i] + s2[j] 实际上如果两个都要删除,说明s1[0:i] s2[0:j]这些字符中都找不到s1[i],s2[j],那么DP[i-1][j]中一定选中了s2[j]进行删除,DP[i][j-1]中一定选中了s1[i]删除。那么,这种情况就和1)2)重合了,可以不必重复考虑。
    因此DP[i][j] = min{DP[i-1][j] + s1[i], DP[i][j-1] + s2[j]}

Initialization

在上述算法中,假设的已知条件作为起点才能驱动整个循环。
首先DP[0][0] =s1[0] == s2[0] ? 0: s1[0] + s2[0];

  • 初始化DP[0][0-n]
    即看做s1只有一个字符,s2[0-n)。假设s2中第i个字符与s1[0] 第一次相等(如不存在i = n),那么对于0 < j < n and j != i 都有DP[0][j] = DP[0][j-1] + s2[j] 当j == iDP[0][j] = DP[0][j-1] -s1[0]s1[0]不需要再删除)
  • 初始化DP[0-n][0]
    同上

Example

s1 = se, s2 = ea, 求DP[1][1] = ?

//i = 0, j = 0
DP[0][0] = s + e; //216

//i = 0, j = 1
DP[0][1] = DP[0][0] + a  //s1[0] = s  s2中没有s字符DP[0][j] = DP[0][j-1] + s2[j] 
313

//i = 1, j = 0
DP[1][0] = DP[0][0] - s2[0]//s2[0] = e, s1中第一个为e的字符index = 1 DP[i][0] = DP[i-1][j] - s2[0]
115

//i = 1, j = 1
DP[1][1] = min{DP[0][1] + e,  DP[1][0] + a} //s1[i] != s2[j] , min{删除e, 删除a}
min{414, 212} = 212
class Solution {
public:
int minimumDeleteSum(string s1, string s2) {
	vector<vector<int>> dp(s1.size(), vector<int>(s2.size(), 10000));
	dp[0][0] = s1[0] == s2[0] ? 0 : s1[0] + s2[0];
	bool flag = dp[0][0] == 0 ? true : false;
	for (int i = 1; i < s1.size(); i++) {
		if (s1[i] == s2[0] && !flag) {
			dp[i][0] = dp[i - 1][0] - s2[0];
			flag = true;
		}
		else {
			dp[i][0] = dp[i - 1][0] + s1[i];
		}
	}
	flag= dp[0][0] == 0 ? true : false;
	for (int i = 1; i < s2.size(); i++) {
		if (s1[0] == s2[i] && !flag) {
			dp[0][i] = dp[0][i - 1] - s1[0];
			flag = true;
		}
		else {
			dp[0][i] = dp[0][i - 1] + s2[i];
		}
	}
	for (int i = 1; i < s1.size(); i++) {
		for (int j = 1; j < s2.size(); j++) {
			if (s1[i] == s2[j]) {
				dp[i][j] = dp[i - 1][j - 1];
			}
			else {
				dp[i][j] = min(dp[i - 1][j] + s1[i], dp[i][j - 1] + s2[j]);
			}
		}
	}
	return dp[s1.size() - 1][s2.size() - 1];
}
};


给定两个字符串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 的结果,比答案更大。

注意:

  • 0 < s1.length, s2.length <= 1000
  • 所有字符串中的字符ASCII值在[97, 122]之间。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值