72. Edit Distance

参考:https://labuladong.gitbook.io/algo/dong-tai-gui-hua-xi-lie/zhuang-tai-ya-suo-ji-qiao

问题:

给定两个字符串,求出由一个字符串转化为另一个字符串的最短编辑距离。(编辑操作次数)

有以下三种编辑:

  • 插入
  • 删除
  • 替换
Example 1:
Input: word1 = "horse", word2 = "ros"
Output: 3
Explanation: 
horse -> rorse (replace 'h' with 'r')
rorse -> rose (remove 'r')
rose -> ros (remove 'e')

Example 2:
Input: word1 = "intention", word2 = "execution"
Output: 5
Explanation: 
intention -> inention (remove 't')
inention -> enention (replace 'i' with 'e')
enention -> exention (replace 'n' with 'x')
exention -> exection (replace 'n' with 'c')
exection -> execution (insert 'u')

  

解法:DP(动态规划)

1.确定【状态】:

  • 字符串S1的第i个字符:word1[i]
  • 字符串S2的第j个字符:word2[j]

2.确定【选择】:分两种情况

  • word1[i] == word2[j]:操作数不变
    • 不做任何操作,继续比较两字符串的下一个字符:i++,j++
  • word1[i] != word2[j]:以下三种操作之一,操作数+1
    • 插入操作:给word1[i]之前,插入word2[j] -> 那么下一次比较 i(不动),j++(j的下一位)
    • 删除操作:删除word1[i]                        -> 那么下一次比较 i(i的下一位),j(不动)
    • 替换操作:将word1[i]替换成word2[j]       -> 那么继续比较两字符串的下一位:i++,j++

3. dp[i][j]的含义:

对比到word1的第 i 个字符,word2的第 j 个字符,使得两个字符串相同,所做的最少编辑次数。

4. 状态转移:

dp[i][j]=

  • (word1[i] == word2[j]):=上一个状态的次数:dp[i-1][j-1]
  • (word1[i] != word2[j]):=min {
    • 上一个状态,通过:插入操作 得到:dp[i][j-1] + 1
    • 上一个状态,通过:删除操作 得到:dp[i-1][j] + 1
    • 上一个状态,通过:替换操作 得到:dp[i-1][j-1] + 1    }

5. base case:

  • dp[0][j]=j:S1始终在第0位上,要通过 j 步插入操作,才能与S2到第 j 位一致。
  • dp[i][0]=i:S2始终在第0位上,S1要通过 i 步删除操作,才能与S2到第 0 位一致。

代码参考:

 1 class Solution {
 2 public:
 3     //dp[i][j]:until s1[i],s[j],the minimal steps has been taken to make two words same.
 4     //case_1: s1[i]==s2[j]: =dp[i-1][j-1]
 5     //case_2: s1[i]!=s2[j]: min(case_2_1, case_2_2, case_2_3)
 6     //       case_2_1:insert-> =dp[i][j-1]+1 // s1[i] insert s2[j], 
 7                                            //then next comparation is -> i stop, j+1
 8     //       case_2_2:delete-> =dp[i-1][j]+1 // s1[i] delete, 
 9                                            //then next comparation is -> i+1, j stop
10     //       case_2_3:replace-> =dp[i-1][j-1]+1 // s1[i] replace to s2[j], 
11                                            //then next comparation is -> i+1, j+1
12     //base case:
13     //dp[i][0]=i
14     //dp[0][j]=j
15     int minDistance(string word1, string word2) {
16         int m=word1.length(), n=word2.length();
17         vector<vector<int>> dp(m+1, vector<int>(n+1, 0));
18         for(int i=0; i<=m; i++) dp[i][0]=i;
19         for(int j=0; j<=n; j++) dp[0][j]=j;
20         
21         for(int i=1; i<=m; i++) {
22             for(int j=1; j<=n; j++) {
23                 if(word1[i-1]==word2[j-1]) {
24                     dp[i][j] = dp[i-1][j-1];
25                 } else {
26                     dp[i][j] = min(dp[i][j-1]+1, dp[i-1][j]+1);
27                     dp[i][j] = min(dp[i][j], dp[i-1][j-1]+1);
28                 }
29             }
30         }
31         return dp[m][n];
32     }
33 };

♻️ 优化:

空间复杂度:2维->1维

去掉 i 

压缩所有行到一行。

左上角dp[i-1][j-1]会被下面的dp[i][j-1]覆盖,因此引入变量pre,在更新dp[i][j-1]之前,保存dp[i-1][j-1]

⚠️ 注意:在每一行最开始的初始化,也要注意pre要初始化为每一行上一行的开头元素dp[i][0]=i

 

代码参考:

 1 class Solution {
 2 public:
 3     //dp[i][j]:until s1[i],s[j],the minimal steps has been taken to make two words same.
 4     //case_1: s1[i]==s2[j]: =dp[i-1][j-1]
 5     //case_2: s1[i]!=s2[j]: min(case_2_1, case_2_2, case_2_3)
 6     //       case_2_1:insert-> =dp[i][j-1]+1 // s1[i] insert s2[j], 
 7                                            //then next comparation is -> i stop, j+1
 8     //       case_2_2:delete-> =dp[i-1][j]+1 // s1[i] delete, 
 9                                            //then next comparation is -> i+1, j stop
10     //       case_2_3:replace-> =dp[i-1][j-1]+1 // s1[i] replace to s2[j], 
11                                            //then next comparation is -> i+1, j+1
12     //base case:
13     //dp[i][0]=i
14     //dp[0][j]=j
15     int minDistance(string word1, string word2) {
16         int m=word1.length(), n=word2.length();
17         vector<int> dp(n+1, 0);
18         for(int j=0; j<=n; j++) dp[j]=j;
19         
20         for(int i=1; i<=m; i++) {
21             int pre=dp[0];//pre line's first item
22             dp[0] = i;//dp[i][0]=i
23             for(int j=1; j<=n; j++) {
24                 int tmp = dp[j];
25                 if(word1[i-1]==word2[j-1]) {
26                     dp[j] = pre;
27                 } else {
28                     dp[j] = min(dp[j-1]+1, dp[j]+1);
29                     dp[j] = min(dp[j], pre+1);
30                 }
31                 pre = tmp;
32             }
33         }
34         return dp[n];
35     }
36 };

 

posted @ 2020-09-05 15:14  habibah_chang  阅读(142)  评论(0编辑  收藏  举报