演算法筆記 編輯距離

2021-08-07 12:53:38 字數 3247 閱讀 8305

原題:

給出兩個單詞word1和word2,計算出將word1 轉換為word2的最少操作次數。

你總共三種操作方法:

給出 work1=」mart」 和 work2=」karma」

返回 3

下面是兩種思路實現,自頂向上方法和自頂向下方法

不如將問題簡化下,化成規模比較小的問題。

首先,我們先考慮兩個空串,那麼當然就會出現0次。

若其中有乙個為空串,另外乙個為單字元的話,若a為空的話,只要執行一次插入操作,就能達到目的。反之只要執行一次刪除次數操作。

對於非空串來說,我們先考慮只有單字元的a和b,不相等的話就只需要執行一次替換操作,就可以到達目的。

我們將上面操作視為單字元操作

對於雙字元的情況,它可以視作單字元完成後再進行單字元操作的情況。對於有三個字元的,同樣視作雙字元操作完成後再執行單字元判斷操作的情況。以此類推,那麼對於任意長度n的字串,都可以看成n-1字串完成後再進行單字元操作。

這是一種動態規劃的演算法。於是我們就可以使用乙個result[i][j]陣列來表示字串a的從起始到i的子串到匹配字串b從起始到j的子串所需要進行的運算元。

那麼問題來了,我們應該如何表示單字元操作呢?

正如上面定義所說的。當a為空的話,那麼就執行插入。那什麼時候會出現這麼一種情況?

當a的長度比b要小的時候,那麼我們就需要進行插入操作。

當我們用result[i][j]形式表示該操作的時候,就表示為result[i][j] = result[i][j-1]+1

(為什麼這裡是result[i][j-1] 而不是result[i - 1][j]?

因為我們result[i][j-1]表示a的前i個和b的前j-1的已經匹配好的了,所以當j-1加1後,i就比較小了。所以就需要進行插入操作。

) 同理,當a的長度比b要大的時候,我們就要需要刪除操作

表示為result[i][j] = result[i-1][j] + 1;

那麼替換呢?

很簡單,兩個一樣長,如果不相等就替換。

表示為result[i][j] = result[i-1][j-1] + x(x = 0 or 1)

我們可以用下圖來表示他們之間的關係

迭代演算法

public class solution 

for(int j = 0 ; j <= word2.length() ; j++)

for(int i = 1 ; i <= word1.length() ; i++) else }}

return result[word1.length()][word2.length()];

}public int

min(int t1,int t2,int t3)

}

當然,不止那麼一種演算法。我們剛才是通過從後往前推的方式推導出結果的。

我們也可以換一種思路,從前往後退的方式進行推導。

對於空串的處理,我們和上面的處理是一樣的

那麼就對於不為空串的字串就有

刪除a第乙個字元後,將a從2到尾的子串和b從1到尾的子串變成相同字串

刪除b第乙個字元後,將a從1到尾的子串和b從2到尾的子串變成相同字串

替換a或b第乙個字元後,將a從2到尾的子串和b從2到尾的子串變成相同字串

增加b第乙個字元到a第乙個字元後,將a從1到尾的子串和b從2到尾的子串變成相同字串

增加a第乙個字元到b第乙個字元後,將a從2到尾的子串和b從1到尾的子串變成相同字串

綜上,我們可以得出如下結論

一步操作後,將a從1到尾的子串和b從2到尾的子串變成相同的字串

一步操作後,將a從2到尾的子串和b從1到尾的子串變成相同的字串

一步操作後,將a從2到尾的子串和b從2到尾的子串變成相同的字串

那麼我們就可以通過遞迴的方式得出結果

遞迴演算法

public

class solution

public

intcaculatedistance(string word1,int begin1,int end1,string word2,int begin2,int end2)

else

}if(begin2 > end2)

else

}//相等直接跳下乙個

if(word1.charat(begin1) == word2.charat(begin2))else

}public

intmin(int t1,int t2,int t3)

}

上面的演算法就是《程式設計之美》裡面提供的演算法。

不過我們可以發現,它在每一次呼叫的時候都會進行三次的自我遞迴呼叫。不難發現他的時間複雜度是o(3^n)。是一種很糟糕的演算法。對於特別大的資料,耗時是非常大的。那麼有沒有改進措施呢?

該書也給出了一種改進的方法。

如下圖是部分展開的遞迴呼叫

可以發現,圈中的兩個子問題被重複計算了。那麼我們就像能不能減少計算的量。既然重複計算了,那麼第二次計算就是沒有必要的。所以我們最有效的方法就是把計算結果儲存起來。當第二次呼叫的時候,我們直接用就好了。

下面是優化後的演算法

帶記憶的遞迴演算法

public

class solution

}return caculatedistance(word1,0,word1.length()-1,

word2,0,word2.length() - 1);

}public

intcaculatedistance(string word1,int begin1,int end1,string word2,int begin2,int end2)

if(begin1 > end1)

else

}if(begin2 > end2)

else

}if(word1.charat(begin1) == word2.charat(begin2))else

}public

intmin(int t1,int t2,int t3)

}

編輯距離及編輯距離演算法

編輯距離概念描述 編輯距離,又稱levenshtein距離,是指兩個字串之間,由乙個轉成另乙個所需的最少編輯操作次數。許可的編輯操作包括將乙個字元替換成另乙個字元,插入乙個字元,刪除乙個字元。例如將kitten一字轉成sitting sitten k s sittin e i sitting g 俄...

編輯距離及編輯距離演算法

include include include using namespace std const int max 1001 int maxlen max max int maxlen string str1,string str2 return maxlen len1 len2 int main ...

編輯距離及編輯距離演算法

include include include using namespace std const int max 1001 int maxlen max max int maxlen string str1,string str2 return maxlen len1 len2 int main ...