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')
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(); } };