zoukankan      html  css  js  c++  java
  • 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 };
  • 相关阅读:
    区间树
    最大流
    单源最短路径
    散列表
    最小生成树
    软件体系结构2
    软件体系结构
    Leetcode 687.最长同值路径
    Leetcode 686.重复叠加字符串匹配
    Python测试框架
  • 原文地址:https://www.cnblogs.com/habibah-chang/p/13618298.html
Copyright © 2011-2022 走看看