题目链接:力扣72-编辑距离
前情提要:
因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。
dp五部曲。
1.确定dp数组和i下标的含义。
2.确定递推公式。
3.dp初始化。
4.确定dp的遍历顺序。
5.如果没有ac打印dp数组 利于debug。
每一个dp题目如果都用这五步分析清楚,那么这道题就能解出来了。
题目思路:
如果你做过力扣583-两个字符串的删除操作,或者看过我那篇题解,那么做本题会轻松很多。
本题与力扣583不同的就是,本题可以对单词有三种操作,删除、替换、添加。
而力扣583只有一种操作,就是删除。
本题题目要求使word1转化为word2相同所使用的最少操作数。
使用dp五部曲系统分析一下。
1.确定dp数组和i下标的含义。
dp[i] [j] 是指使i - 1结尾的word1和以j - 1为结尾的word2相同所操作的最少次数。
注意这里是以i - 1为结尾,j - 1为结尾。至于为什么要这样设置dp数组看看我这篇题解力扣718-最长重复子数组(Java详细题解)-CSDN博客。
2.确定递推公式。
子序列问题都要考虑word1[i - 1] 是否等于 word2[j - 1]的情况。
-
相等的情况。
既然最后结尾的元素相等,那么就要在以前一个为结尾的元素的字符串中操作了。
所以dp[i] [j] = dp[i - 1] [j - 1];
-
不相等的情况
不相等我们就要操作元素了,具体的操作情况有三种。
-
删除
-
增加
-
替换
其实删除和增加是相互的,你对word1删除使其和word2相同,其实也可以使word2增加使其和word1相同。
那么肯定有人想我为什么不删然后再加,那么所用的操作数肯定就多了,而且没有意义。
所以其实这里删除和添加选一个就行了,我这里用的就是删除,具体删除哪个我们不能确定,是由递推公式帮我们确定删除元素多的那个。
删除的情况就跟力扣583一模一样了就是dp[i] [j] = Math.min(dp[i - 1] [j] + 1,dp[i] [j - 1] + 1);
替换的话我们就得额外考虑了。
当我们最后一个元素不相同,需要替换,我们肯定是替换其中的一个使其与另一个相同。所以dp[i] [j] = dp[i - 1] [j - 1] + 1;
因为我们替换最后一个元素,所以只需要在前一个元素的最少操作数加一即可。
综上所述:
dp[i] [j] = Math.min(dp[i - 1] [i - 1] + 1,Math.min(dp[i - 1] [j],dp[i] [j - 1]));
-
3.dp初始化。
由递推公式可以看出dp[i] [j] 是由dp[i] [j - 1]或者dp[i - 1] [j]或dp[i - 1] [j - 1]推出。
所以在二维dp数组里就由他的上方左方和左上方三个方向推出。
那么起始位置就是第一行和第一列;
dp[i] [0] dp[0] [j] 指的是空串和另一个字符串相同时操作的最少次数。
那么使他们相同的最少操作次数就是让有元素的字符串的元素全部删掉。
所以dp初始化为
for(int i = 0;i <= s.length();i ++){
dp[i][0] = i;
}
for(int i = 0;i <= t.length();i ++){
dp[0][i] = i;
}
4.确定dp的遍历顺序。
由递推公式可以看出dp[i] [j] 是由dp[i] [j - 1]或者dp[i - 1] [j]或dp[i - 1] [j - 1]推出。
所以在二维dp数组里就由他的上方左方和左上方三个方向推出。
所以遍历顺序一定是从左到右,从上到下。
5.如果没有ac打印dp数组 利于debug。
其实前面的题都是用来铺垫本题,如果前面题理解了,那么做本题不会很难。
这一篇博客就到这了,如果你有什么疑问和想法可以打在评论区,或者私信我。
我很乐意为你解答。那么我们下篇再见!