题目描述
https://leetcode-cn.com/problems/minimum-ascii-delete-sum-for-two-strings/
解法
自顶向下的动态规划
看了这道题,其实很像寻找两个字符串的最长公共子序,因为这里要找最小ASCII码删除和,就像寻找最长公共子序一样,因为多出来的字符,它们肯定要删除的,而如果不是最长公共子序,必然删除得到的AscII码值之和必然更大。
所以题目可以使用两个字符串的最长公共子序的类似解法来做:
class Solution {
int[][]memo;
public int minimumDeleteSum(String s1, String s2) {
//有想法一定要先执行,就像寻找最长公共子序一样因为多出来的字符,它们肯定要删除的
//而不是最长公共子序,必然删除得到的AscII码值之和必然更大
int m = s1.length(), n = s2.length();
// 备忘录值为 -1 代表未曾计算
memo = new int[m][n];
for (int[] row : memo)
Arrays.fill(row, -1);
return dp(s1,0,s2,0);
}
// 递归函数,自顶向下的递推,其问题的定义:计算 s1[i..] 和 s2[j..] 的最少步数
int dp(String s1, int i, String s2, int j) {
if (i == s1.length() ){
int res=0;
for(int k=j;k<s2.length();k++){
res += s2.charAt(k);
}
return res;//全部删除
}
if(j == s2.length()) {
int res = 0;
for(int k=i;k<s1.length();k++){
res += s1.charAt(k);
}
return res;//全部删除,此时s2为“”,则需要把s1全删除
}
// 如果之前计算过,则直接返回备忘录中的答案
if (memo[i][j] != -1) {
return memo[i][j];
}
// 根据 s1[i] 和 s2[j] 的情况做选择
if (s1.charAt(i) == s2.charAt(j)) {
memo[i][j] = dp(s1, i + 1, s2, j + 1);
} else {
memo[i][j] = Math.min(
dp(s1, i + 1, s2, j)+s1.charAt(i),//只需删除1个
dp(s1, i, s2, j + 1)+s2.charAt(j)//只需删除1个
//两个都删除的情况被包含在上面
);
}
return memo[i][j];
}
}