D48|动态规划之编辑距离

2024-01-02 15:16:55

583.两个字符串的删除操作

初始思路:

? ? ? ? 大概能想到定义dp数组为最少的删除次数

????????想不明白递归公式应该怎么推导

题解复盘:

? ? ? ? 第一种思路:dp[i][j]所需要删除元素的最少次数.

? ? ? ? 递归公式五部曲;

? ? ? ? 1)dp数组的定义:

????????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

那最后当然是取最小值,所以当word1[i - 1] 与 word2[j - 1]不相同的时候,递推公式:dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1});

????????3)如何初始化:

????????dp[i][0]:word2为空字符串,以i-1为结尾的字符串word1要删除多少个元素,才能和word2相同呢,很明显dp[i][0] = i

class Solution {
    public int minDistance(String word1, String word2) {
        char[] wc1 = word1.toCharArray();
        char[] wc2 = word2.toCharArray();
        int[][] dp = new int[wc1.length+1][wc2.length+1];
        for(int i = 0;i<wc1.length+1;i++){
            dp[i][0] = i;
        }
        for(int j = 0;j<wc2.length+1;j++){
            dp[0][j] = j;
        }
        for(int i = 1;i<wc1.length+1;i++){
            for(int j = 1;j<wc2.length+1;j++){
                if(wc1[i-1]==wc2[j-1]){
                    dp[i][j] = dp[i-1][j-1];
                }else{
                    dp[i][j] = Math.min(dp[i-1][j]+1,Math.min(dp[i][j-1]+1,dp[i-1][j-1]+2));
                }
            }
        }
        return dp[wc1.length][wc2.length];
    }
}

第二种思路:只要求出两个字符串的最长公共子序列长度即可,那么除了最长公共子序列之外的字符都是必须删除的,最后用两个字符串的总长度减去两个最长公共子序列的长度就是删除的最少步数。


72.编辑距离

初始思路:

1)dp[i][j]表示最少的操作数

2)推导递推公式:

? ? ? ? 相等:dp[i][j] = dp[i-1][j-1];

? ? ? ? 不相等:

? ? ? ? ? ? ? 可以进行删除:dp[i][j] = dp[i-1][j]+1;

? ? ? ? ? ? ? ?插入:

? ? ? ? ? ? ? ?替换:

怎么理解?

题解复盘:

重点看不懂的部分:

  • 操作二:word2删除一个元素,那么就是以下标i - 1为结尾的word1 与 j-2为结尾的word2的最近编辑距离 再加上一个操作。

即?dp[i][j] = dp[i][j - 1] + 1;

这里有同学发现了,怎么都是删除元素,添加元素去哪了。

word2添加一个元素,相当于word1删除一个元素,例如?word1 = "ad" ,word2 = "a"word1删除元素'd'?和?word2添加一个元素'd',变成word1="a", word2="ad", 最终的操作数是一样! dp数组如下图所示意的:

            a                         a     d
   +-----+-----+             +-----+-----+-----+
   |  0  |  1  |             |  0  |  1  |  2  |
   +-----+-----+   ===>      +-----+-----+-----+
 a |  1  |  0  |           a |  1  |  0  |  1  |
   +-----+-----+             +-----+-----+-----+
 d |  2  |  1  |
   +-----+-----+

操作三:替换元素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;

综上,当?if (word1[i - 1] != word2[j - 1])?时取最小的,即:dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;

?3)初始化:

那么dp[i][0]就应该是i,对word1里的元素全部做删除操作,即:dp[i][0] = i;

同理dp[0][j] = j,此处可以理解为0字符需要增添相应的字符才能和word2相同等价于word2删除字符的操作数。

class Solution {
    public int minDistance(String word1, String word2) {
        char[] wc1 = word1.toCharArray();
        char[] wc2 = word2.toCharArray();
        int[][] dp = new int[wc1.length+1][wc2.length+1];
        for(int i = 0;i<wc1.length+1;i++){
            dp[i][0] = i;
        }
        for(int j = 0;j<wc2.length+1;j++){
            dp[0][j] = j;
        }
        for(int i = 1;i<wc1.length+1;i++){
            for(int j = 1;j<wc2.length+1;j++){
                if(wc1[i-1]==wc2[j-1]){
                    dp[i][j] = dp[i-1][j-1];
                }else{
                    dp[i][j] = Math.min(dp[i-1][j]+1,Math.min(dp[i][j-1]+1,dp[i-1][j-1]+1));
                }
            }
        }
        return dp[wc1.length][wc2.length];
    }
}

文章来源:https://blog.csdn.net/Q77ian/article/details/135336218
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。