1. 程式人生 > >【Leetcode】【DP】 72. Edit Distance / 編輯距離

【Leetcode】【DP】 72. Edit Distance / 編輯距離

Given two words word1 and word2, find the minimum number of operations required to convert word1 to word2.

You have the following 3 operations permitted on a word:

  1. Insert a character
  2. Delete a character
  3. Replace a character

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')

Given two words word1 and word2, find the minimum number of operations required to convert word1 to word2.

 

給定兩個字串,求編輯距離。編輯距離即是對字串進行:刪除一個字元,插入一個字元,替換一個字元 的操作,每個操作計數1,從字串1到字串2的運算元即為編輯距離。

 

可畫圖分析:

如,由字串A:please 和字串B:apple。長度為m和n。

首先構建一個 (m+1) x (n+1) 的二維陣列,定義 

dp [i][j] 表示字串A的前i個組成的子字串和字串B的前j個組成的子字串的編輯距離

dp[i][j] (此處取dp[2][2],即 pl 和 ap )分析如下:

首先之前已經求得了dp [2-1] [2] (p和ap的編輯距離),dp [2] [2-1] (pl和a), dp [2-1] [2-1] (p和a)。

 

  •  pl -> ap 可先 ap -> p (等同於p->ap) ,再加上一個 插入l 的操作,即為 dp [1] [2]  + 1 ,擴充套件為 dp [i] [j] = dp [i-1] [j] + 1
  •  pl -> ap 可先 pl -> a ,再加上一個 插入p 的操作,即為 dp [2] [1]  + 1 ,擴充套件為 dp [i] [j] = dp [i] [j-1] + 1
  •  pl -> ap 可先 p -> a ,再加上一個 將 l 換為 p 的操作,即為 dp [1] [1]  + 1 ,擴充套件為 dp [i] [j] = dp [i-1] [j-1] + 1。但如果替換操作中的A[2] = B[2], 如 pl -> al 的操作,p -> a ,再加上一個 將 l 換為 l 的操作,即無需操作,dp [1] [1]  + 0 ,擴充套件為 dp [i] [j] = dp [i-1] [j-1] + 0。定義這個0/1運算元為cost,if A[i] == B[j] , cost = 0, 否則cost = 1。dp [i] [j] = dp [i-1] [j-1] + cost

綜上,欲得到最小編輯距離,dp =  三種情況的最小值。

故進行以下幾步:

 

  1. 構建 (m+1) x (n+1) 的二維陣列
  2. 初始狀態:第一行(由A空字串到B的編輯距離)/第一行。
  3. 由dp公式遞推
  4. 返回最右下值

總公式:

    int minDistance(string word1, string word2) {
        int m = word1.size();
        int n = word2.size();
        if(m==0 || n==0)
            return m+n;
        vector<vector<int>> dp(m+1, vector<int>(n+1, 0));
        
        for(int i=0; i<=n; i++) {
            dp[0][i] = i;
        }
        for(int i=0; i<=m; i++) {
            dp[i][0] = i;
        }
        int cost = 0;
        for(int i=1; i<=m; i++) {
            for(int j=1; j<=n; j++) { 
                if(word1[i-1] == word2[j-1])    // 此處檢查word1的當前字元和word2的當前字元是否相等
                    cost = 0;  // 相等則說明,當前段的編輯轉換 等於 從word1的前一段轉換到word2的前一段
                else 
                    cost = 1;  // 否則需要進行一次轉換操作,即已知A和B的前一段轉換需要x操作,則當前需要再對後面這個字母進行一次替換操作
                dp[i][j] = min(dp[i-1][j-1]+cost, min(dp[i-1][j]+1, dp[i][j-1]+1));
            }
        }
        return dp[m][n]; // 矩陣為 m+1 x n+1, 故最終返回dp[m][n]
    }

 

易錯處:

dp初始化時需要先將第一行第一列初始化,因為後續遞推式有 i-1 和 j-1 項。

dp長度時 m+1,n+1的,記住迴圈的邊界在 i<=m,j<=n。以及最後返回值是dp[m][n]

求三項最小值應用兩個min組合來得到