1. 程式人生 > >leetCode 72.Edit Distance (編輯距離) 解題思路和方法

leetCode 72.Edit Distance (編輯距離) 解題思路和方法

Edit Distance

Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.)

You have the following 3 operations permitted on a word:

a) Insert a character
b) Delete a character
c) Replace a character

 別人的思路:
自然語言處理(NLP)中,有一個基本問題就是求兩個字串的minimal Edit Distance, 也稱Levenshtein distance。受到一篇Edit Distance介紹文章的啟發,本文用動態規劃求取了兩個字串之間的minimal Edit Distance. 動態規劃方程將在下文進行講解。 

1. what is minimal edit distance?
簡單地說,就是僅通過插入(insert)、刪除(delete)和替換(substitute)個操作將一個字串s1變換到另一個字串s2的最少步驟數。熟悉演算法的同學很容易知道這是個動態規劃問題。 
其實一個替換操作可以相當於一個delete+一個insert,所以我們將權值定義如下:
I  (insert):1
D (delete):1
S (substitute):2

2. example:
intention->execution
Minimal edit distance:
delete i ; n->e ; t->x ; insert c ; n->u 求和得cost=8

3.calculate minimal edit distance dynamically
思路見註釋,這裡D[i,j]就是取s1前i個character和s2前j個character所得minimal edit distance
三個操作動態進行更新:
D(i,j)=min { D(i-1, j) +1, D(i, j-1) +1 , D(i-1, j-1) + s1[i]==s2[j] ? 0 : 2};中的三項分別對應D,I,S。(詳見我同學的部落格)
因為本題的替換操作權重同樣為1,故字元不相等+1即可。

程式碼如下:

public class Solution {
    public int minDistance(String word1, String word2) {
        //邊界條件
        if(word1.length() == 0)
    		return word2.length();
    	if(word2.length() == 0)
    		return word1.length();
        /*
         * 本題用動態規劃的解法
         * f[i][j]表示word1的前i個單詞到word2前j個單詞的最短距離
         * 狀態轉移方程:f[i][j] = 
         */
        
        int[][] f = new int[word1.length()][word2.length()];
        boolean isEquals = false;//是否已經有相等
        for(int i = 0 ; i < word2.length(); i++){
            //如果相等,則距離不增加
            if(word1.charAt(0) == word2.charAt(i) && !isEquals){
                f[0][i] = i > 0 ? f[0][i-1]:0;//不能從0開始
                isEquals = true;
            }else{
                f[0][i] = i > 0 ? f[0][i-1]+1:1;
            }
        }
        isEquals = false;//是否已經有相等
        for(int i = 1 ; i < word1.length(); i++){
            //如果相等,則距離不增加
            if(word1.charAt(i) == word2.charAt(0) && !isEquals){
                f[i][0] =  f[i-1][0];//不能從0開始
                isEquals = true;
            }else{
                f[i][0] = f[i-1][0]+1;
            }
        }
        
        for(int i = 1; i < word1.length();i++){
            for(int j = 1; j < word2.length(); j++){
                if(word1.charAt(i) == word2.charAt(j)){
                    f[i][j] = f[i-1][j-1];//相等的話直接相等
                }else{
                    f[i][j] = f[i-1][j-1]+1;
                }
                //然後與從f[i-1][j]+1,f[i][j-1]+1比較,取最小值
                f[i][j] = Math.min(f[i][j],Math.min(f[i-1][j]+1,f[i][j-1]+1));
            }
        }
        return f[word1.length()-1][word2.length()-1];
    }
}