题目
题目链接
题目的意思是,随机给两串字符串,然后你需要将删除两串字符串里面的若干个字符,使这两串字符串相等。同时,要求你删除的字符ASCII码之和最小。
思路
感觉到后面刷的动态规划题目,越来越有挑战性了。。一开始我也是一脸懵逼,好在看了一波solution和discuss然后自己复现了。
要求ASCII值最小,说明这个必定只有一个解。用动态规划解决问题关键在于怎么把它转化为dp问题,同时找到状态转移方程。
我们可以用dp[i][j]
表示先使用s1串中的前i个字符,s2中的前j个字符。然后我们可以通过前面的状态得到后面的,最后的dp[i][j]
就是最后的结果。
首先初始化,我们可以先将一个字符串置空,可以得到第一行和第一列的信息,这是sea和eat的信息:
我们将会有三个方向(上、左、左上)得到,总的话是四种情况:
- 首先是
s1[i-1] == s2[j-1]
,新增的两个字符相等的情况下,我们没有必要删除之前的结果,因此dp[i][j] = dp[i-1][j-1]
- 接下来都是
s1[i-1] != s2[j-1]
时的情况,我们取三者最小值:
- 从保留s2串,删除s1串的字符,
dp[i][j] = dp[i-1][j] + s1.codePointAt(i-1)
- 从保留s1串,删除s2串的字符,
dp[i][j] = dp[i][j-1] + s1.codePointAt(j-1)
- 删除s1、s2串的字符,
dp[i][j] = dp[i-1][j-1] + s1.codePointAt(i-1) + s2.codePointAt(j-1)
- 从保留s2串,删除s1串的字符,
最后我们推算得到最终结果dp[i][j]
。
代码实现(Java)
/**
* dp[i][j],i表示s1前i个字符,j表示s2前j个字符
* @param s1
* @param s2
* @return
*/
public int minimumDeleteSum(String s1, String s2) {
int dp[][] = new int[s1.length() + 1][s2.length() + 1];
//初始化
for(int i = 0; i <= s1.length(); i++) {
for(int k = 0; k < i; k++) {
dp[i][0] += s1.codePointAt(k);
}
}
for(int j = 0; j <= s2.length(); j++) {
for(int k = 0; k < j; k++) {
dp[0][j] += s2.codePointAt(k);
}
}
//进行状态转移
for(int i = 1; i <= s1.length(); i++) {
for(int j = 1; j <= s2.length(); j++) {
if(s1.charAt(i-1) == s2.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1];
} else {
dp[i][j] = Math.min(Math.min(dp[i-1][j] + s1.codePointAt(i-1), dp[i][j-1] + s2.codePointAt(j-1)),
dp[i-1][j-1] + s1.codePointAt(i-1) + s2.codePointAt(j-1));
}
}
}
// for(int i = 0; i <= s1.length(); i++) {
// for(int j = 0; j <= s2.length(); j++) {
// System.out.print(dp[i][j] + " " );
// }
// System.out.println("");
// }
return dp[s1.length()][s2.length()];
}