1. 程式人生 > >相近字串的匹配--編輯距離問題

相近字串的匹配--編輯距離問題

首先需要解決的問題是:定義一個函式(cost function)計算兩個字串的相差程度。
一個合理的設計是:計算從一個字串改成另一個字串需要經過的步數。

更改的三種基本型別

  • 替代:更改一個字元,如shot->spot
  • 插入: 插入一個字元,如ago->agog
  • 刪除:刪除一個字元,如hour->our

這樣計算出從字串P變到字串T總共需要多少基本型別,就是編輯距離。

這種相似字串的匹配演算法似乎很難,但是藉助DP思想,問題將非常簡潔。又是見證奇蹟的時候。

遞迴形式的編輯距離問題

i,j為字串字首子串的最後一個字元。
字串P(長度為m)變T(長度為n),我們以P

i,Tj表示下標分別為i,j的字元。
定義一個函式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]的編輯距離。因為PiTj不匹配,將指向P的指標前挪一位,指向T的指標不動。+1表示的代價是刪除Pi的代價。

  • D[i,j-1]+1表示的是在P
    i
    後新增一個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,比單獨比較實現程式碼簡潔得多。