LeetCode72. 编辑距离

Posted machine_gun_lin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode72. 编辑距离相关的知识,希望对你有一定的参考价值。

考虑用一个二维dp数组表示所需的最小操作次数。

dp[i][j]表示将word1的前i个字符转换为word2的前j个字符所需要的最少操作次数。

由于操作的顺序对于最后操作的结果没有影响,所以我们假设操作总是从word1的前面字符操作到word1的后面字符。

  1. 如果word1的第i个字符等于word2的第j个字符,所以对于第i个字符实际上是没有操作的,
    那么编辑距离就取决于word1的1 ~ i - 1的字符和word2的1 ~ j - 1的字符,
    所以我们得到: dp[i][j] = dp[i - 1][j - 1]
    这个方程表示当word1的第i个字符等于word2的第j个字符,编辑距离就是将word1的1~i-1个字符改为
    word2的1~j-1的编辑距离。 (至于是怎么编辑的,我们不需要管,我们只需要计算编辑距离就行了,下面同理)

  2. 如果word1的第i个字符和word2的第j个字符不相等。那么有三种操作:

    (1)如果要将word1的 1 ~ i 转换为word2的 1 ~ j 的最后一步是:在word1的1 ~ i个字符之后增加一个字符word1[i + 1] (这个字符必然是word2[j]),这就比将word1的1i转换为word2的1j-1的编辑距离多一(这里可能有点难以理解,这么说吧,word1最开始是1i,word2是1j-1,由于word1转换为word2的最后一步是加入一个字符word1[i + 1]或者说是word2[j],所以编辑距离就是word1的1i到word2的1j-1的编辑距离加一!) 得到状态转移方程: 编辑距离dp[i][j] = dp[i][j - 1] + 1

    (2) 如果要将word1的1 ~ i 转换为word2的 1 ~ j的最后一步是: 删掉word1的第i个字符,那么编辑距离就是将word1的1~i-1个字符转换为word2的1~j个字符的编辑距离加一(加一这部操作表示删除word1[i]), 因此我们得到状态转移方程: dp[i][j] = dp[i - 1][j] + 1

    (3) 如果要将word1的1 ~ i 转换为word2的 1 ~ j的最后一步是: 修改word1的第i个字符,那么编辑距离就是将word1的1i-1个字符转换为word2的1j-1个字符的编辑距离加一。可以这么理解:经过将word1的1i-1个字符转换为word2的1j-1个字符的编辑距离之后,word2多了一个字符word[j],偏偏word1的最后一个字符word[i]和word2[j]不相等,好在我们只需要一步修改操作就可以完成所有转换。 所以状态转移方程是:dp[i][j] = dp[i - 1][j - 1] + 1

有了状态转移方程,只需要再对dp数组的边界做初始化,然后就可以开始递推啦。

边界可以这么确定:假设word1和word2两个字符串其中一个字符串为空,另一个字符串长度为x,那么dp[x][0]或者dp[0][x]显然就是x了。
把长度为x的字符串全部删掉也好,把空字符串加x个字符使得它和另一个字符串相等也好,最少的操作次数必然是x。

这样我们就找到了数组递推边界,开始考虑递推:
从上面的第2点(word1的第i个字符不等于word2的第j个字符)的分析可以发现,dp[i][j]是从dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]
三个状态得到的,而且都是在前一个状态的基础上加一(分别表示添加、删除、修改操作),由于我们的dp数组表示操作的最少次数,
所以我们要取三个前置状态的最小值再+1。

因此当word1的第i个字符不等于word2的第j个字符时,我们得到状态转移方程:dp[i][j] = min(dp[i - 1][j - 1], min(dp[i][j - 1], dp[i - 1][j]) + 1

如果当word1的第i个字符和word2的第j个字符相等呢,这个情况我们可以单独判断,如果相等,就让dp[i][j]等于dp[i - 1][j - 1]就好了。

代码如下:

class Solution {
public:
    int minDistance(string word1, string word2) {
        int n = word1.size(), m = word2.size();
        vector<vector<int>> dp(n + 1, vector<int>(m + 1));
        for(int i = 1; i <= n; ++i) {      //初始化边界
            dp[i][0] = i;
        }
        for(int i = 1; i <= m; ++i) {      //初始化边界
            dp[0][i] = i;
        }
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= m; ++j) {
                dp[i][j] = min(dp[i - 1][j - 1], min(dp[i][j - 1], dp[i - 1][j])) + 1;
                if(word1[i - 1] == word2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1];
                }
            }
        }
        return dp.back().back();           //等价于return dp[n][m]; 
    }
};

以上是关于LeetCode72. 编辑距离的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 72 编辑距离

Leetcode 72.编辑距离

leetcode 72. Edit Distance 编辑距离(中等)

LeetCode-72. 编辑距离

*Leetcode 72 编辑距离

*Leetcode 72 编辑距离