zoukankan      html  css  js  c++  java
  • 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]; 
        }
    };
    
  • 相关阅读:
    React在componentDidMount里面发送请求
    React 术语词汇表
    React里受控与非受控组件
    React和Vue等框架什么时候操作DOM
    【LeetCode】79. Word Search
    【LeetCode】91. Decode Ways
    【LeetCode】80. Remove Duplicates from Sorted Array II (2 solutions)
    【LeetCode】1. Two Sum
    【LeetCode】141. Linked List Cycle (2 solutions)
    【LeetCode】120. Triangle (3 solutions)
  • 原文地址:https://www.cnblogs.com/linrj/p/13233244.html
Copyright © 2011-2022 走看看