leetcode 72.編輯距離

編輯距離可以說是動態規劃算法中經典的、知名的題目了,題目難度也不小,是一道很好的動態規劃的題目。很可能會出現在面試中動態規劃的考察上。

題目

給定兩個單詞 word1word2,計算出將 word1 轉換成 word2 所使用的最少操作數 。

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

  1. 插入一個字符
  2. 刪除一個字符
  3. 替換一個字符

示例 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[i][j] 表示將 word1 的前 i 個字符轉換成 word2 的前 j 個字符所需要的最少操作數。

接着就是寫出狀態轉移方程,動態規劃題目的難度或者說複雜度往往是由狀態轉移方程的複雜度決定的。
對於本題:
dp[i][j] = word1[i] == word2[j] ? dp[i-1][j-1] : min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1])+1;

或者展開成下面的形式,可能更加直觀:

if(word1[i] == word2[j])
	dp[i][j] = dp[i-1][j-1];
else
	dp[i][j] = min(
		dp[i][j-1]+1, // 對應插入字符操作
		dp[i-1][j]+1, // 對應刪除字符操作
		dp[i-1][j-1]+1 // 對應替換字符操作
	);

其中,

if(word1[i] == word2[j])
	dp[i][j] = dp[i-1][j-1];

的含義是,如果 word1 的第 i 個字符和 word2 的第 j 個字符相等,那麼將 word1 的前 i 個字符轉換成 word2 的前 j 個字符所需要的最少操作就等於將 word1 的前 i-1 個字符轉換成 word2 的前 j-1 個字符所需要的最少操作。

其中,

if(word1[i] != word2[j]){
	dp[i][j] = min(
		dp[i][j-1]+1, // 對應插入字符操作
		dp[i-1][j]+1, // 對應刪除字符操作
		dp[i-1][j-1]+1 // 對應替換字符操作
	);
}

先說插入字符操作,dp[i][j] = dp[i][j-1]+1,對於這個式子你可能會產生這樣的疑問?dp[i][j-1] 表示的是將 word1 前 i 個字符轉換成 word2 前 j-1 個字符,那現在在 word1 中插入一個等於 word2[j] 的字符,表示的應該是 dp[i+1][j] 的含義呀。那是因爲你插入的這個新字符並不屬於原生的 word1,這還得回到 dp[i][j] 的定義上:它表示的是將 word1 的前 i 個字符轉換成 word2 的前 j 個字符所需要的最少操作數。

而刪除操作就不一樣了,它刪除的就是 word1 中的原生字符(不用考慮刪除的是之前插入字符的情況,這是一對冗餘無效的操作,不會出現在 dp 所表示的最少操作中),所以它對應的是 dp[i-1][j]+1,同理,替換操作替換的也是 word1 中的原生字符。

參考代碼:

class Solution {
    public int minDistance(String word1, String word2) {
        int[][] dp = new int[word1.length()+1][word2.length()+1];
        for(int i = 0; i < dp.length; ++i) dp[i][0] = i;
        for(int i = 0; i < dp[0].length; ++i) dp[0][i] = i;
        for(int i = 1; i <= word1.length(); ++i){
            for(int j = 1; j <= word2.length(); ++j){
                if(word1.charAt(i-1) == word2.charAt(j-1)) dp[i][j] = dp[i-1][j-1];
                else dp[i][j] = min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + 1;
            }
        }
        return dp[word1.length()][word2.length()];
    }
    private int min(int a, int b, int c){
        if(a > b) a = b;
        return a < c ? a : c;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章