Refrence : Dynamic Programming Algorithm (DPA) for Edit-Distance 编辑距离 关于两个字符串s1,s2的差别,可以通过计算他们的最小编辑距离来决定。 所谓的编辑距离: 让s1和s2变成相同字符串需要下面操作的最小次数。 1. 把某个字符ch1变成ch2 2. 删除某个字符 3. 插入某个字符 例如 s1 = “12433” 和s2=”1233”; 则可以通过在s2中间插入4得到12433与s1一致。 即 d(s1,s2) = 1 (进行了一次插入操作) 编辑距离的性质 计算两个字符串s1+ch1, s2+ch2的编辑距离有这样的性质: 1. d(s1,””) = d(“”,s1) = |s1| d(“ch1”,”ch2”) = ch1 == ch2 ? 0 : 1; 2. d(s1+ch1,s2+ch2) = min( d(s1,s2)+ ch1==ch2 ? 0 : 1 , d(s1+ch1,s2), d(s1,s2+ch2) ); 第一个性质是显然的。 第二个性质: 由于我们定义的三个操作来作为编辑距离的一种衡量方法。 于是对ch1,ch2可能的操作只有 1. 把ch1变成ch2 2. s1+ch1后删除ch1 d = (1+d(s1,s2+ch2)) 3. s1+ch1后插入ch2 d = (1 + d(s1+ch1,s2)) 对于2和3的操作可以等价于: _2. s2+ch2后添加ch1 d=(1+d(s1,s2+ch2)) _3. s2+ch2后删除ch2 d=(1+d(s1+ch1,s2)) 因此可以得到计算编辑距离的性质2。 复杂度分析 从上面性质2可以看出计算过程呈现这样的一种结构(假设各个层用当前计算的串长度标记,并假设两个串长度都为 n ) 可以看到,该问题的复杂度为指数级别 3 的 n 次方,对于较长的串,时间上是无法让人忍受的。 分析: 在上面的结构中,我们发现多次出现了 (n-1,n-1), (n-1,n-2)……。换句话说该结构具有重叠子问题。再加上前面性质2所具有的最优子结构。符合动态规划算法基本要素。因此可以使用动态规划算法把复杂度降低到多项式级别。 动态规划求解 首先为了避免重复计算子问题,添加两个辅助数组。 一. 保存子问题结果。 M[ |s1| ,|s2| ] , 其中M[ i , j ] 表示子串 s1(0->i) 与 s2(0->j) 的编辑距离 二. 保存字符之间的编辑距离. E[ |s1|, |s2| ] , 其中 E[ i, j ] = s[i] = s[j] ? 0 : 1 三. 新的计算表达式 根据性质1得到 M[ 0,0] = 0; M[ s1i, 0 ] = |s1i|; M[ 0, s2j ] = |s2j|; 根据性质2得到 M[ i, j ] = min( m[i-1,j-1] + E[ i, j ] , m[i, j-1] , m[i-1, j] ); 复杂度 从新的计算式看出,计算过程为 i=1 -> |s1| j=1 -> |s2| M[i][j] = …… 因此复杂度为 O( |s1| * |s2| ) ,如果假设他们的长度都为n,则复杂度为 O(n^2)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int _Min(int a,int b,int c)
{
int min=a;
if (b <min)
min=b;
if(c <min)
min=c;
return min;
}
int ComputeDistance(char s[],char t[])
{
int n = strlen(s);
int m = strlen(t);
//int d[][] = new int[n + 1, m + 1]; // matrix
int **d = (int **)malloc((n+1) * sizeof(int *));
for(int i=0; i<=n; ++i)
{
d[i] = (int *)malloc((m+1) * sizeof(int));
}
// Step 1
if (n == 0)
{
return m;
}
if (m == 0)
{
return n;
}
// Step 2
for (int i = 0; i <= n; i++)
{
d[i][0] =i;
}
for (int j = 0; j <= m; d[0][j] = j++)
{
d[0][j] =j;
}
// Step 3
for (int i = 1; i <= n; i++)
{
//Step 4
for (int j = 1; j <= m; j++)
{
// Step 5
int cost = (t[j-1] == s[i-1]) ? 0 : 1;
// Step 6
d[i][j] = _Min(d[i-1][j]+1, d[i][j-1]+1,d[i-1][j-1]+cost);
}
}
// Step 7
return d[n][m];
}
int main(int argc, char *argv[])
{
char a[9999];
char b[9999];
printf("请输入字符串1/n");
scanf("%s",&a);
printf("请输入字符串2/n");
scanf("%s",&b);
int result= ComputeDistance(a,b);
printf("%d/n",result);
system("PAUSE");
return 0;
}