题目概述

 题目链接:点我做题
题解
  这个题也是离谱。。。主要是要把状态定义出来并且把状态转移方程写出来太困难了,不过不要紧,这篇题解的目的就是为了给第一次做这个题的人理清思路、给复习的人(疑似只有我)快速回忆思路用的,因此会讲清楚这个题的思路。
   首先,字符串有关的dp题目,状态一般都设置成从第一个字符到第i个字符的反映问题的东西,这里有两个字符串,因此考虑设置二维数组
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        ,
       
       
        j
       
       
        )
       
      
      
       f(i,j)
      
     
    f(i,j),看看题意是求
    
     
      
       
        w
       
       
        o
       
       
        r
       
       
        d
       
       
        1
       
      
      
       word1
      
     
    word1到
    
     
      
       
        w
       
       
        o
       
       
        r
       
       
        d
       
       
        2
       
      
      
       word2
      
     
    word2的编辑距离,那么
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        ,
       
       
        j
       
       
        )
       
      
      
       f(i,j)
      
     
    f(i,j)就代表考虑
    
     
      
       
        w
       
       
        o
       
       
        r
       
       
        d
       
       
        1
       
      
      
       word1
      
     
    word1的前i个字符变到
    
     
      
       
        w
       
       
        o
       
       
        r
       
       
        d
       
       
        2
       
      
      
       word2
      
     
    word2的前j个字符的编辑距离。假设
    
     
      
       
        w
       
       
        o
       
       
        r
       
       
        d
       
       
        1
       
      
      
       word1
      
     
    word1的长度是n,
    
     
      
       
        w
       
       
        o
       
       
        r
       
       
        d
       
       
        2
       
      
      
       word2
      
     
    word2的长度是m,那么我们要的答案就是
    
     
      
       
        f
       
       
        (
       
       
        n
       
       
        ,
       
       
        m
       
       
        )
       
      
      
       f(n,m)
      
     
    f(n,m).
   建出状态来以后,要考虑的就是状态转移方程,就要回到题目中允许的三种操作:插入一个字符、删除一个字符、替换一个字符。再考虑一个对称性的问题,word1变到word2的编辑距离和word2变到word1的编辑距离显然是相等的,因为每一步都是可逆的,那么我们求编辑距离可以同时对word1操作、对word2操作,当word1和word2相同的时候,总操作次数就是编辑距离。
   如果上面这一大串没看懂,没关系,意思就是说word1和word2可以双向奔赴,思考时不必保持word2不变让word1变成word2。
   破处了这个枷锁以后,我们再来看这个题,显然word1和word2同时都能操作的话,
    
     
      
       
        3
       
       
        ∗
       
       
        2
       
       
        =
       
       
        6
       
      
      
       3*2=6
      
     
    3∗2=6,就有6种操作了,但是考虑到对称性:word1插入一个字符等价于word2删除一个字符、word2插入一个字符等价于word1删除一个字符、word1替换一个字符等价于word2替换一个字符。所以实际上可以只用三种操作来描述:
- w o r d 1 word1 word1插入一个字符:
- w o r d 2 word2 word2插入一个字符
- 
     
      
       
        
         w
        
        
         o
        
        
         r
        
        
         d
        
        
         1
        
       
       
        word1
       
      
     word1替换一个字符
 有了这些操作我们再来联想状态转移方程,既然每次只能变一个字符,那么 f ( i , j ) f(i,j) f(i,j)一定是由 f ( i − 1 , j ) 、 f ( i , j − 1 ) 、 f ( i − 1 , j − 1 ) f(i - 1,j)、f(i,j-1)、f(i-1,j-1) f(i−1,j)、f(i,j−1)、f(i−1,j−1)这三个状态转移来的。
  考虑
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        −
       
       
        1
       
       
        ,
       
       
        j
       
       
        )
       
      
      
       f(i-1,j)
      
     
    f(i−1,j)变成
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        ,
       
       
        j
       
       
        )
       
      
      
       f(i,j)
      
     
    f(i,j),怎么变呢,
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        −
       
       
        1
       
       
        ,
       
       
        j
       
       
        )
       
      
      
       f(i-1,j)
      
     
    f(i−1,j)的意思是由
    
     
      
       
        w
       
       
        o
       
       
        r
       
       
        d
       
       
        2
       
      
      
       word2
      
     
    word2的前j个字符变成
    
     
      
       
        w
       
       
        o
       
       
        r
       
       
        d
       
       
        1
       
      
      
       word1
      
     
    word1的前i-1个字符的编辑距离,那然后再让此时的
    
     
      
       
        w
       
       
        o
       
       
        r
       
       
        d
       
       
        1
       
      
      
       word1
      
     
    word1的前i-1个字符再插入一个
    
     
      
       
        w
       
       
        o
       
       
        r
       
       
        d
       
       
        1
       
      
      
       word1
      
     
    word1的第i个字符不就行了.
   因此此时编辑距离等于由word2的前j个字符变为word1的前i-1个字符的编辑距离加上word1的前i-1个字符再插入word1的第i个字符这一操作的编辑距离,因此如果由
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        −
       
       
        1
       
       
        ,
       
       
        j
       
       
        )
       
      
      
       f(i-1,j)
      
     
    f(i−1,j)递推到
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        ,
       
       
        j
       
       
        )
       
      
      
       f(i,j)
      
     
    f(i,j),编辑距离就是
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        ,
       
       
        j
       
       
        )
       
       
        =
       
       
        f
       
       
        (
       
       
        i
       
       
        −
       
       
        1
       
       
        ,
       
       
        j
       
       
        )
       
       
        +
       
       
        1
       
      
      
       f(i,j) = f(i - 1,j) + 1
      
     
    f(i,j)=f(i−1,j)+1.
   考虑
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        ,
       
       
        j
       
       
        −
       
       
        1
       
       
        )
       
      
      
       f(i,j - 1)
      
     
    f(i,j−1)变成
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        ,
       
       
        j
       
       
        )
       
      
      
       f(i,j)
      
     
    f(i,j),同上,先让word1的前i个字符变为word2的前j-1个字符,然后让word2的前j-1个字符执行插入word2的第j个字符的操作就可以了,因此此时的编辑距离就等于由word1的前i个字符变为word2的前j-1个字符的编辑距离
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        ,
       
       
        j
       
       
        −
       
       
        1
       
       
        )
       
      
      
       f(i,j-1)
      
     
    f(i,j−1)再加上插入word2的第j个字符这一操作的编辑距离1,即
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        ,
       
       
        j
       
       
        )
       
       
        =
       
       
        f
       
       
        (
       
       
        i
       
       
        ,
       
       
        j
       
       
        −
       
       
        1
       
       
        )
       
       
        +
       
       
        1
       
      
      
       f(i,j)=f(i,j-1)+1
      
     
    f(i,j)=f(i,j−1)+1
   考虑
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        −
       
       
        1
       
       
        ,
       
       
        j
       
       
        −
       
       
        1
       
       
        )
       
      
      
       f(i-1,j-1)
      
     
    f(i−1,j−1)变成
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        ,
       
       
        j
       
       
        )
       
      
      
       f(i,j)
      
     
    f(i,j),这里也只剩一种操作了,就是替换,首先让word1的前i-1个字符变为word2的前j-1个字符,然后将word1的第i个字符替换为word2的第j个字符(如果word1的第i个字符和word2的第j个字符相同则不用替换),这样就完成了由word1的前i个字符变为word2的前j-1个字符。
   此时编辑距离就等于由word1的前i-1个字符变为word2的前j-1个字符的编辑距离
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        −
       
       
        1
       
       
        ,
       
       
        j
       
       
        −
       
       
        1
       
       
        )
       
      
      
       f(i-1,j-1)
      
     
    f(i−1,j−1)再加上word1的第i个字符替换为word2的第j个字符这一操作的编辑距离1(如果word1的第i个字符和word2的第j个字符相等就不用加上这一步了),
 
     
      
       
        
         i
        
        
         f
        
        
         (
        
        
         w
        
        
         o
        
        
         r
        
        
         d
        
        
         1
        
        
         [
        
        
         i
        
        
         −
        
        
         1
        
        
         ]
        
        
         =
        
        
         =
        
        
         w
        
        
         o
        
        
         r
        
        
         d
        
        
         2
        
        
         [
        
        
         j
        
        
         −
        
        
         1
        
        
         ]
        
        
         )
        
        
         ,
        
        
         f
        
        
         (
        
        
         i
        
        
         ,
        
        
         j
        
        
         )
        
        
         =
        
        
         f
        
        
         (
        
        
         i
        
        
         −
        
        
         1
        
        
         ,
        
        
         j
        
        
         −
        
        
         1
        
        
         )
        
        
        
         e
        
        
         l
        
        
         s
        
        
         e
        
        
         ,
        
        
         f
        
        
         (
        
        
         i
        
        
         ,
        
        
         j
        
        
         )
        
        
         =
        
        
         f
        
        
         (
        
        
         i
        
        
         −
        
        
         1
        
        
         ,
        
        
         j
        
        
         −
        
        
         1
        
        
         )
        
        
         +
        
        
         1
        
       
       
         if (word1[i - 1] == word2[j - 1]),f(i,j) = f(i - 1,j - 1)\\ else,f(i,j) = f(i - 1,j - 1) + 1 
       
      
     if(word1[i−1]==word2[j−1]),f(i,j)=f(i−1,j−1)else,f(i,j)=f(i−1,j−1)+1
   由于求的是最小编辑距离,因此f(i,j) = min(1.,2.,3.).
   接下来考虑初始条件,如果一个word1的前0个字符(也就是个空字符)变为word2的前j个字符,显然只有把word2的j个字符依次插入这一种途径了,因为编辑距离就是执行j次插入的编辑距离:
    
     
      
       
        f
       
       
        (
       
       
        0
       
       
        ,
       
       
        j
       
       
        )
       
       
        =
       
       
        j
       
      
      
       f(0,j) = j
      
     
    f(0,j)=j;
   同理,如果把word2的前0个字符变为word1的前i个字符,编辑距离为
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        ,
       
       
        0
       
       
        )
       
       
        =
       
       
        i
       
      
      
       f(i,0)=i
      
     
    f(i,0)=i;
   这个dp优化不了空间复杂度,因为状态转移时同时有
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        −
       
       
        1
       
       
        ,
       
       
        j
       
       
        −
       
       
        1
       
       
        )
       
      
      
       f(i - 1,j - 1)
      
     
    f(i−1,j−1)和
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        ,
       
       
        j
       
       
        −
       
       
        1
       
       
        )
       
      
      
       f(i,j-1)
      
     
    f(i,j−1)这两项,这要求dp[j - 1]同时储存上一行的
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        −
       
       
        1
       
       
        ,
       
       
        j
       
       
        −
       
       
        1
       
       
        )
       
      
      
       f(i - 1,j - 1)
      
     
    f(i−1,j−1)和本行的
    
     
      
       
        f
       
       
        (
       
       
        i
       
       
        ,
       
       
        j
       
       
        −
       
       
        1
       
       
        )
       
      
      
       f(i,j - 1)
      
     
    f(i,j−1),前者要求内层循环从大到小遍历,后者要求内层循环从小到大遍历,矛盾。
 代码:
class Solution {
public:
    int minDistance(string word1, string word2) 
    {
        /*
        f(i,j) 考虑word1的前i个字符变成word2的前j个字符的编辑距离
        若word1的长度为n word2的长度为m
        答案就是f(n,m)
        首先要明确 六种操作可以归类为3种操作
        对word1插入一个字符等价于对word2删除一个字符
        对word2插入一个字符等价于对word1删除一个字符
        对word1替换一个字符等价于对word2替换一个字符
        三种操作:
        1.对word1插入一个字符
        2.对word2插入一个字符
        3.对word1替换一个字符
        然后来分析状态转移方程
        1.f(i - 1,j)变到f(i,j),
        这个过程是word2的前j个字符变到word1的前i-1个字符,然后再让word1的前i-1个字符插入第i个字符
        显然编辑距离是由word2的前j个字符变为word1的前i-1个字符的编辑距离再加word1后面再插入一个字符的1,
        即f(i,j) = f(i - 1,j) + 1
        2.f(i,j - 1)变到f(i,j),
        这个过程是word1的前i个字符变成word2的前j-1个字符,然后再让word2的前j-1个字符插入第j个字符
        显然编辑距离是前一步的编辑距离再加1,
        即f(i,j) = f(i,j - 1) + 1
        3.f(i - 1, j - 1)变到f(i,j),
        这个过程是修改word1的第i个字符使其与word2的第j个字符相等,然后让word1的前i-1个字符变为word2的前j-1个字符
        如果本来word1[i - 1] == word2[j - 1] 那就不用做这一次又该操作了
        所以f(i,j) = f(i - 1, j - 1), if word1[i - 1] == word2[j - 1]
            f(i,j) = f(i - 1, j - 1) + 1, else
        只有这三种变化方法 所以f(i,j) = min(1.2.3.)
        初始条件 f(i, 0) = i f(0,j) = j
        */
        int n = word1.size();
        int 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 j = 1; j <= m; ++j)
        {
            dp[0][j] = j;
        }
        for (int i = 1; i <= n; ++i)
        {
            for (int j = 1; j <= m; ++j)
            {
                if (word1[i - 1] != word2[j - 1])
                {
                    dp[i][j] = mymin(dp[i - 1][j], 
                    dp[i][j - 1], dp[i - 1][j - 1]) + 1;
                }
                else
                {
                    dp[i][j] = mymin(dp[i - 1][j] + 1, 
                    dp[i][j - 1] + 1, dp[i - 1][j - 1]);
                }
            }
        }
        return dp[n][m];
    }
    int mymin(int a, int b, int c)
    {
        if (a < b)
        {
            if (a < c)
            {
                return a;
            }
            else
            {
                return c;
            }
        }
        /*a > b*/
        else
        {
            if (b > c)
            {
                return c;
            }
            else
            {
                return b;
            }
        }
    }
};
时间复杂度:
    
     
      
       
        O
       
       
        (
       
       
        m
       
       
        ∗
       
       
        n
       
       
        )
       
      
      
       O(m*n)
      
     
    O(m∗n)
 空间复杂度:
    
     
      
       
        O
       
       
        (
       
       
        m
       
       
        ∗
       
       
        n
       
       
        )
       
      
      
       O(m*n)
      
     
    O(m∗n)










