1. 程式人生 > 實用技巧 >72. 編輯距離(Edit Distance)

72. 編輯距離(Edit Distance)

題目描述:

給你兩個單詞word1 和word2,請你計算出將word1轉換成word2 所使用的最少運算元。

你可以對一個單詞進行如下三種操作:

插入一個字元
刪除一個字元
替換一個字元

示例1:

輸入:word1 = "horse", word2 = "ros"
輸出:3
解釋:
horse -> rorse (將 'h' 替換為 'r')
rorse -> rose (刪除 'r')
rose -> ros (刪除 'e')
示例2:

輸入:word1 = "intention", word2 = "execution"
輸出:5
解釋:
intention -> inention (刪除 't')

inention -> enention (將 'i' 替換為 'e')
enention -> exention (將 'n' 替換為 'x')
exention -> exection (將 'n' 替換為 'c')
exection -> execution (插入 'u')

解題思路:

  這道題是一道典型的動態規劃題目,有一句話不是說字串相關的題目百分之八十都是動態規劃嗎(~-~)

  因為有兩個字串,所以dp陣列要使用二維陣列,dp[i][j]表示以word1[i],word2[j]結束的子串需要做的最少運算元。因為可以想到,當word1[i]等於word2[j],不需要做任何操作,所以dp[i][j]等於dp[i-1][j-1];當word1[i]不等於word2[j]時,三種方法都可以應對當前的局面,假設把word2變成word1,即所有操作都在word2上執行:

  當插入一個字元時,可以假設在word2[j]之後插入了word1[i],這時word1[i]就已經不用考慮了,只用考慮word2[j]結束的子串和word1[i-1]結束的子串。因此這時需要的運算元等於dp[i-1][j] + 1。

  當刪除一個字元時,可以假設直接刪除word2[j],這時只用考慮word2[j-1]結束的子串和word1[i]結束的子串。因此這時需要的運算元等於dp[i][j-1] + 1。

  當替換一個字元時,可以假設把word2[j],替換為了word1[i],這時只用考慮word2[j-1]結束的子串和word1[i-1]結束的子串。因此這時需要的運算元等於dp[i-1][j-1] + 1。

  選擇哪個操作取決於哪個操作的值最小,因此只需要令dp[i][j] = min({dp[i-1][j],dp[i][j-1],dp[i-1][j-1]}) + 1即可。注意構造dp陣列時在設定好邊界,邊界從word1或word2為空串時開始。

  程式碼如下:

class Solution {
public:
    int minDistance(string word1, string word2) {
        vector<vector<int>> dp{word1.size() + 1, vector<int>(word2.size() + 1)};
        for (int i = 1; i != word2.size() + 1; ++i)
            dp[0][i] = i;
        for (int i = 1; i != word1.size() + 1; ++i)
            dp[i][0] = i;
        
        for (int i = 1; i != word1.size() + 1; ++i)
            for (int j = 1; j != word2.size() + 1; ++j) {
                if (word1[i-1] == word2[j-1])
                    dp[i][j] = dp[i-1][j-1];
                else {
                    dp[i][j] = min({dp[i-1][j-1], dp[i][j-1], dp[i-1][j]}) + 1;
                }
            }
            
        return dp.back().back();
    }
};