最小編輯距離問題(Edition Distance)
注:這篇部落格討論的演算法是怎樣求解兩個字串的最小編輯距離,其目的是為了下一篇的虛擬DOM,來做一個預備工作,這裡主要討論的用
什麼是最小編輯距離:
給定一個長度為m和n的兩個字串,設有以下幾種操作:替換(R),插入(I)和刪除(D)且都是相同的操作。尋找到轉換一個字串插入到另一個需要修改的最小(操作)數量。這個數量就可以被視為最小編輯距離。如:acd與ace的
遞迴實現:
我們來討論一下情況:
當
當
1. 在
2. 在
3. 更改
4. 刪除
5. 刪除
情況搞清楚了,程式碼我們非常快的就能寫出:
#include <iostream>
#include <cmath>
using namespace std;
inline int getMin (int a, int b, int c)
{
return min(min(a, b), c);
}
int calcDistance(char* A, char* B, int m, int n)
{
if (m == 0 && n == 0)
return 0;
if (m == 0)
return n;
if (n == 0)
return m;
int caseA = calcDistance(A, B, m - 1 , n) + 1;
int caseB = calcDistance(A, B, m, n - 1) + 1;
int caseC = calcDistance(A, B, m - 1, n - 1) + (A[m] != B[n]);
return getMin(caseA, caseB, caseC);
}
int main ()
{
char s1[20], s2[20];
cin>>s1>>s2;
cout<<calcDistance(s1, s2, strlen(s1), strlen(s2))<<endl;
return 0;
}
但是這種方法的缺點在哪裡呢,就像求解斐波那契數列那樣,遞迴造成了重複計算(如:我們可以在不同的遞迴函式中呼叫已經呼叫過的函式),我們再來看看最小編輯距離問題具有重疊子問題,最優子結構,所以我們可以用動態規劃來進行求解,這樣就避免了重複計算的問題。
利用動態規劃:
動態規劃的方式,我們只是對遞迴進行一下變形,也就是對我們已經求得的值進行儲存,首先我們要初始化一張表出來,也就是一個二維陣列,N[A.length + 1][B.length + 1]
。
形成表如圖:(
我們來總結一下我們上面所述幾種情況的表現,可以分為4類:
1.
2. 更改
3. 刪除
4. 刪除
最終
min(情況1 || 情況2, 情況3, 情況4)
的最小值,並且程式碼如下:
int calcDistanceDP (char* A, char* B)
{
int m = strlen(A), n = strlen(B);
// 生成表
int *T = (int *)malloc(m * n * sizeof(int));
// 賦初始值
for (int i = 0; i <= m; i++)
for (int j = 0; j <= n; j++)
*(T + i * n + j) = 0;
for (int i = 0; i <= m; i++)
*(T + i * n) = i;
for (int i = 0; i <= n; i++)
*(T + i) = i;
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
int cost = (int)A[i] != B[j];
int caseA = *(T + i * n + j + 1) + 1;
int caseB = *(T + (i + 1) * n + j) + 1;
int caseC = *(T + i * n + j) + cost;
*(T + (i + 1) * n + j + 1) = getMin(caseA, caseB, caseC);
}
}
return *(T + m * n - 1);
}
演算法複雜度為