代码随想录算法训练营第五十六天|583. 两个字符串的删除操作、72. 编辑距离
两个字符串的删除操作
583. 两个字符串的删除操作
文章讲解:https://programmercarl.com/0583.%E4%B8%A4%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E5%88%A0%E9%99%A4%E6%93%8D%E4%BD%9C.html
题目链接:https://leetcode.cn/problems/delete-operation-for-two-strings/
视频讲解:https://www.bilibili.com/video/BV1we4y157wB/
自己看到题目的第一想法
- dp数组下标和定义:
- dp[i][j]:i-1位置的word1下,j-1位置下的word2下相同所需的最小步数(删除多少元素)。
- 推导公式:
- 相等的情况下,不需要删除,和前面2位i-1 j-1的值一样大
- word1[i - 1] == word2[j - 1],dp[i][j] = dp[i-1][j-1]
- 不相等的情况下,需要删除,可以删除i也可以删除j,删除i时最小值要加1 删除j最小值也要加一
- word1[i - 1] != word2[j - 1],dp[i][j] = Math.min(dp[i-1][j] + 1,dp[i][j-1] + 1)
- 相等的情况下,不需要删除,和前面2位i-1 j-1的值一样大
- 初始化值:因为是取的坐上和左边上边,因此要求出dp[i][0]和dp[0][j]的值
- dp[i][0]的值直接取i的值,dp[0][j]的值直接取j的值。
- for(int i = 0; i <= charWord1.length; i++) dp[i][0] = i;
- for(int j = 0; j <= charWord2.length; j++) dp[0][j] = j;
- 遍历顺序:因为是从小到大,因此从0开始遍历
public int minDistance(String word1, String word2) {// dp数组下标和定义// dp[i][j]:i-1位置的word1下,j-1位置下的word2下相同所需的最小步数(删除多少元素)。// 推导公式// 相等的情况下,不需要删除,和前面2位i-1 j-1的值一样大// word1[i - 1] == word2[j - 1],dp[i][j] = dp[i-1][j-1]// 不相等的情况下,需要删除,可以删除i也可以删除j,删除i时最小值要加1 删除j最小值也要加一// word1[i - 1] != word2[j - 1],dp[i][j] = Math.min(dp[i-1][j] + 1,dp[i][j-1] + 1)char[] charWord1 = word1.toCharArray();char[] charWord2 = word2.toCharArray();int[][] dp = new int[charWord1.length + 1][charWord2.length + 1];for(int i = 0; i <= charWord1.length; i++){dp[i][0] = i;}for(int j = 0; j <= charWord2.length; j++){dp[0][j] = j;}for(int i = 1; i <= charWord1.length; i++){for(int j = 1; j <= charWord2.length; j++){if(charWord1[i - 1] == charWord2[j - 1]){dp[i][j] = dp[i-1][j-1];}else{dp[i][j] = Math.min(dp[i-1][j] + 1,dp[i][j-1] + 1);}}}return dp[charWord1.length][charWord2.length];
}
看完代码随想录之后的想法
不想等的时候有3种情况,我只考虑到了2种情况。
三种情况:
情况一:删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。
递推公式:dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1});
又因为 dp[i][j - 1] + 1 = dp[i - 1][j - 1] + 2 。所以递推公式dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);
自己实现过程中遇到哪些困难
ac
编辑距离
72. 编辑距离
文章讲解:https://programmercarl.com/0072.%E7%BC%96%E8%BE%91%E8%B7%9D%E7%A6%BB.html
题目链接:https://leetcode.cn/problems/edit-distance/
视频讲解:https://www.bilibili.com/video/BV1qv4y1q78f/
自己看到题目的第一想法
动态规划
确定dp数组以及下标定义
dp[i][j]:i-1位置的word1下j-1的位置的word2下的word1转成word2所使用的最小操作数。
不能纬数组分3种情况,只能二维数组分3种情况,每次判断长度,长的话删除,短的话插入,相同的话更换
确定递推公式
这里就推导不出来了
看完代码随想录之后的想法
- dp数组定义和自己看到题目时的想法一致:dp[i][j]:i-1位置的word1下j-1的位置的word2下的word1转成word2所使用的最小操作数。
- 递推公式:
分两种情况,word1[i-1] == word2[j-1]以及 word1[i-1] != word2[j-1]。
相等时:dp[i][j] = dp[i-1][j-1]。
不相等时:
分三种情况:插入一个字符;删除一个字符;替换一个字符。
因为插入和删除所需的操作是一样的,因此上述三种情况只考虑删除和替换就可以了。
删除的情况分2种,删word1和删word2。dp[i][j] = dp[i-1][j] + 1和dp[i][j-1] + 1。
替换的情况只分一种,因为替换要把word1的位置转换成word2,dp[i][j] = dp[i-1][j] + 1。 - 初始化值,因为递推左上角往右边推,因此dp[i][0] = i;dp[0][j] = j;
自己实现过程中遇到哪些困难
删除的逻辑自己能理解并写出来,替换的逻辑没理解对,还要看一下替换的逻辑。
替换逻辑:替换元素,word1替换word1[i - 1],使其与word2[j - 1]相同,此时不用增删加元素。回顾一下,if (word1[i - 1] == word2[j - 1])的时候我们的操作 是 dp[i][j] = dp[i - 1][j - 1] 。那么只需要一次替换的操作,就可以让 word1[i - 1] 和 word2[j - 1] 相同。所以 dp[i][j] = dp[i - 1][j - 1] + 1;
public int minDistance(String word1, String word2) {char[] charWord1 = word1.toCharArray();char[] charWord2 = word2.toCharArray();int[][] dp = new int[charWord1.length + 1][charWord2.length + 1];for(int i = 0; i <= charWord1.length; i++){dp[i][0] = i;}for(int j = 0; j <= charWord2.length; j++){dp[0][j] = j;}for(int i = 1; i <= charWord1.length; i++){for(int j = 1; j <= charWord2.length; j++){if(charWord1[i - 1] == charWord2[j - 1]){// 相等时,只用取前一个节点的值dp[i][j] = dp[i-1][j-1];}else{// 不相等时分2种情况,删和替换// 删dp[i][j] = Math.min(dp[i-1][j] + 1,dp[i][j-1] + 1);// 替换dp[i][j] = Math.min(dp[i][j],dp[i - 1][j - 1] + 1);}}}return dp[charWord1.length][charWord2.length];
}
今日收获&学习时长
距离问题的核心就是定义成i-1,j-1时的位置的最xx值。然后再按照i-1和j-1是否来相等来处理递推逻辑,所有的距离问题都是这样处理的,无非是相等、不等时又分不同的子情况,整体还是都一样的。