動態規劃之編輯距離問題

問題描述:算法

 

對於序列S和T, 它們之間的距離定義爲: 對兩者其一進行幾回如下操做: 1, 刪除一個字符; 2, 插入一個字符; 3, 改變一個字符. 每進行一次操做, 計數增長1. 將S和T變爲相等序列的最小計數就是二者的編輯距離(edit distance)或者叫類似度. 請給出相應算法及其實現. 數組

 

分析:spa

 

假設序列S和T的長度分別爲m和n, 二者的編輯距離表示爲edit[m][n]. 則對序列進行操做時存在如下幾種狀況:3d

  • a, 當S和T的末尾字符相等時, 對末尾字符不須要進行上述定義操做中(亦即"編輯")的任何一個, 也就是不須要增長計數. 則知足條件: edit[m][n] = edit[m - 1][n - 1].
  • b, 當S和T的末尾字符不相等時, 則須要對二者之一的末尾進行編輯, 相應的計數會增長1.
  • b1, 對S或T的末尾進行修改, 以使之與T或S相等, 則此時edit[m][n] = edit[m - 1][n - 1] + 1;
  • b2, 刪除S末尾的元素, 使S與T相等, 則此時edit[m][n] = edit[m - 1][n] + 1;
  • b3, 刪除T末尾的元素, 使T與S相等, 則此時edit[m][n] = edit[m][n - 1] + 1;
  • b4, 在S的末尾添加T的尾元素, 使S和T相等, 則此時S的長度變爲m+1, 可是此時S和T的末尾元素已經相等, 只須要比較S的前m個元素與T的前n-1個元素, 因此知足edit[m][n] = edit[m][n - 1] + 1;
  • b5, 在T的末尾添加S的尾元素, 使T和S相等, 此時的狀況跟b4相同, 知足edit[m][n] = edit[m - 1][n] + 1;
  • c, 比較特殊的狀況是, 當S爲空時, edit[0][n] = n; 而當T爲空時, edit[m][0] = m; 這個很好理解, 例如對於序列""和"abc", 則二者的最少操做爲3, 即序列""進行3次插入操做, 或者序列"abc"進行3次刪除操做.

因此, 以上咱們不難推出編輯距離的動態規劃方程爲:code

, 其中blog

 

因此, 字符串編輯距離的動態規劃算法的遞歸實現能夠用以下的Java代碼表示:遞歸

 1     public static int editDistance(String a, String b) {
 2         if (a == null || b == null) {
 3             return -1;
 4         }
 5         return editDistance(a, a.length() - 1, b, b.length() - 1);
 6     }
 7 
 8     public static int editDistance(String a, int m, String b, int n) {
 9         if (m < 0 || n < 0) {
10             return 1;
11         } else if (a.charAt(m) == b.charAt(n)) {
12             return editDistance(a, m - 1, b, n - 1);
13         } else {
14             return Math.min(Math.min(editDistance(a, m - 1, b, n) + 1, editDistance(a, m, b, n - 1) + 1), editDistance(a, m - 1, b, n - 1) + 1);
15         }
16     }

 

UPDATE:字符串

同時, 由編輯距離的動態規劃方程咱們能夠看出, edit[m][n]能夠由edit[m - 1][n - 1], edit[m - 1][n], edit[m][n - 1]得出, 而若是edit是一個二維數組的話, edit[m][n]能夠由它的上, 左, 左上三個位置的元素經過條件判斷得出. 亦即咱們能夠經過遍歷二維數組, 而後經過回溯來計算當前值.it

例如對於字符串S = "sailn"和T = "failing", 對二維數組進行初始化爲:table

m\n   f a i l i n g
  0 1 2 3 4 5 6 7
s 1 1            
a 2              
i 3              
l 4              
n 5              

由於S[0] = s, T[0] = f, 則S[0] != T[0], 則對應於上述二維矩陣, edit[1][1] = min(edit[0][0], edit[0][1], edit[1][0]) + 1即edit[1][1] = min(0, 1, 1) + 1即edit[1][1] = 0 + 1 = 1. 

m\n   f a i l i n g
  0 1 2 3 4 5 6 7
s 1 1 2 3 4 5 6 7
a 2 2 1          
i 3              
l 4              
n 5              

而對於S[1] = a, T[1] = a, S[1] = T[1], 則對應於二維矩陣, edit[2][2] = edit[1][1], 因此edit[2][2] = 1. 因此按照這種規則, 將上述二維矩陣填滿則以下:

m\n   f a i l i n g
  0 1 2 3 4 5 6 7
s 1 1 2 3 4 5 6 7
a 2 2 1 2 3 4 5 6
i 3 3 2 1 2 3 4 5
l 4 4 3 2 1 2 3 4
n 5 5 4 3 2 2 2 3

因此, 二者的編輯距離爲edit[m][n] = edit[5][7] = 3.

因此, 按照上述思路即動態規劃的回溯解法的Java版本能夠以下進行:

 1     public static int editDistance(String a, String b) {
 2         if (a == null || b == null) {
 3             return -1;
 4         }
 5         int[][] matrix = new int[a.length() + 1][b.length() + 1];
 6         for (int i = 0; i < a.length() + 1; i++) {
 7             for (int j = 0; j < b.length() + 1; j++) {
 8                 if (i == 0) {
 9                     matrix[i][j] = j;
10                 } else if (j == 0) {
11                     matrix[i][j] = i;
12                 } else {
13                     if (a.charAt(i - 1) == b.charAt(j - 1)) {
14                         matrix[i][j] = matrix[i - 1][j - 1];
15                     } else {
16                         matrix[i][j] = 1 + Math.min(Math.min(matrix[i - 1][j], matrix[i][j - 1]), matrix[i - 1][j - 1]);
17                     }
18                 }
19             }
20         }
21         return matrix[a.length()][b.length()];
22     }
相關文章
相關標籤/搜索