代码随想录day54 动态规划
题583 两个字符串的删除操作
1,dp[i][j] 代表以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最少次数。
2, 递推公式:
当word1[i - 1] 与 word2[j - 1]相同的时候,不需要再删除元素,dp[i][j] = dp[i - 1][j - 1];
当word1[i - 1] 与 word2[j - 1]不相同的时候,有三种情况:
情况一:删word1[i - 1],最少操作次数为dp[i - 1][j] + 1
情况二:删word2[j - 1],最少操作次数为dp[i][j - 1] + 1
情况三:同时删word1[i - 1]和word2[j - 1],操作的最少次数为dp[i - 1][j - 1] + 2
最后取3种情况中的最小值。
3, 初始化:
dp[i][0]:word2为空字符串,以word[i-1]为结尾的字符串word1要删除多少个元素,才能和word2相同呢,很明显dp[i][0] = i。同理dp[0][j] = j。
4,本题还有另外一个思路,先求出最长公共子序列的长度max,再用word1.length() - max + word2.length() - max .
class Solution {
public int minDistance(String word1, String word2) {
int[][] dp = new int[word1.length() + 1][word2.length() + 1];
for(int i = 0; i <= word1.length(); i++) {
dp[i][0] = i;
}
for(int j = 0; j <= word2.length(); j++) {
dp[0][j] = j;
}
for(int i = 1; i <= word1.length(); i++) {
char char1 = word1.charAt(i - 1);
for(int j = 1; j <= word2.length(); j++) {
char char2 = word2. charAt(j - 1);
if(char1 == char2) {
dp[i][j] = dp[i - 1][j - 1];
} else {
//删除word1[i-1],删除word[j-1],两个都删除,取这3种情况中的最小。
dp[i][j] = Math.min(Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1), dp[i - 1][j - 1] + 2);
}
}
}
return dp[word1.length()][word2.length()];
}
}
题72 编辑距离
1,编辑距离是用动规来解决的经典题目,这道题目看上去好像很复杂,但用动规可以很巧妙的算出最少编辑距离。
2,同样的,dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]。
3,递推公式:
仍然是分两种情况:
当word1[i - 1] == word2[j - 1], 此时不需要编辑操作,因此dp[i][j] = dp[i - 1][j - 1];
当不想等时就需要编辑,有3种编辑方式:
删除元素:保持word2不变,将word1[i - 1] 删除,就是说不考虑word1[i - 1],则dp[i][j] = dp[i - 1][j] + 1;
插入元素:插入元素相对来说难理解一点,将word2[j-1] 这个字符加到word1[i - 1]的后面,比如"ab" -> “abc”, 当’b’ != 'c’时,将c插入到b的后面,这时只用考虑"ab" -> "ab"所需的最少编辑次数+1(1是代表插入操作),即dp[i][j] = dp[i][j - 1] + 1。
对于增加元素也可以理解为word2删除word2[j-1]这个元素,同时对word1和word2进行编辑,最后得到的字符串相同。
替换元素:将word1[i - 1]替换成word2[j - 1],则dp[i][j] = dp[i - 1][j - 1] + 1。
4,初始化,与两个字符串的删除题目相同,第一行和第一列不再是0, 而是dp[i][0] = i, dp[0][j] = j 。
class Solution {
public int minDistance(String word1, String word2) {
int[][] dp = new int[word1.length() + 1][word2.length() + 1];
for(int i = 0; i <= word1.length(); i++) {
dp[i][0] = i;
}
for(int j = 0; j <= word2.length(); j++) {
dp[0][j] = j;
}
for(int i = 1; i <= word1.length(); i++) {
char char1 = word1.charAt(i - 1);
for(int j = 1; j <= word2.length(); j++) {
char char2 = word2.charAt(j - 1);
if(char1 == char2) {
dp[i][j] = dp[i - 1][j - 1];
} else {
// 3种情况(取最小):
//删除word1[i-1];
//在word1[i-1]后面插入元素word[j-1];
//将word1[i-1]替换为word[j-1].
dp[i][j] = Math.min(Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1), dp[i - 1][j - 1] + 1);
}
}
}
return dp[word1.length()][word2.length()];
}
}