相近字串的匹配--編輯距離問題
阿新 • • 發佈:2019-02-02
首先需要解決的問題是:定義一個函式(cost function)計算兩個字串的相差程度。
一個合理的設計是:計算從一個字串改成另一個字串需要經過的步數。
更改的三種基本型別
- 替代:更改一個字元,如shot->spot
- 插入: 插入一個字元,如ago->agog
- 刪除:刪除一個字元,如hour->our
這樣計算出從字串P變到字串T總共需要多少基本型別,就是編輯距離。
這種相似字串的匹配演算法似乎很難,但是藉助DP思想,問題將非常簡潔。又是見證奇蹟的時候。
遞迴形式的編輯距離問題
以
字串P(長度為m)變T(長度為n),我們以 i,Tj
定義一個函式D[i,j]表示字首子串的編輯距離。
P:[1…i] 1 < i < m
T:[1…j] 1< j < n
總共三種方式右對齊兩個字首字串
如果
Pi=Tj , 子問題變為D[i-1,j-1], 否則為D[i-1,j-1]+1. 意思是:如果最右的字元匹配了,遞迴計運算元串,否則需要替換,代價設為1.D[i-1,j] + 1 表示的是刪除
Pi ,再計算[1…i-1]與[1…j]的編輯距離。因為Pi 與Tj 不匹配,將指向P的指標前挪一位,指向T的指標不動。+1表示的代價是刪除Pi 的代價。- D[i,j-1]+1表示的是在
P 後新增一個Tj ,指向T的指標往左移動一位。因為當前的Tj 通過對P的插入的方式已經匹配了,接著看下一個字元與Pi 的對比操作。
這三類操作都是面對一個字元時候的選擇策略。
D[i,j] = min{D[i-1,j]+Delete( ),D[i,j-1]+Insert( ), D[i-1,j-1]+Replace( )}
Delete:刪除操作
Insert:插入操作
Replace:取代操作,如果字元相同,則為0
如果用遞迴演算法,出口:
D[0,0] = 0;
D[i,0] = i;
D[0,j] = j;
// 遞迴方法實現
int EditDistanceRecursion( char *X, char *Y, int m, int n )
{
// 基本情況
if( m == 0 && n == 0 )
return 0;
if( m == 0 )
return n;
if( n == 0 )
return m;
// 遞迴
int left = EditDistanceRecursion(X, Y, m-1, n) + 1;
int right = EditDistanceRecursion(X, Y, m, n-1) + 1;
int corner = EditDistanceRecursion(X, Y, m-1, n-1) + (X[m-1] != Y[n-1]);
return Minimum(left, right, corner);
}
假設三個操作的代價都是1,則上面的演算法是遞迴的演算法實現。
比較值得注意的巧妙之處是用(X[m-1] != Y[n-1])來表示0,或者1,比單獨比較實現程式碼簡潔得多。