字符串编辑距离: 是一种字符串之间相似度计算的方法。给定两个字符串S、T,将S转换成T所需要的删除,插入,替换操作的数量就叫做S到T的编辑路径。而最短的编辑路径就叫做字符串S和T的编辑距离。
转自这里
关键在于找到该问题的子问题。
举个例子:S=“eeba” T="abac" 我们可以按照这样的步骤转变:(1) 将S中的第一个e变成a;(2) 删除S中的第二个e;(3)在S中最后添加一个c; 那么S到T的编辑路径就等于3。当然,这种变换并不是唯一的,但如果3是所有变换中最小值的话。那么我们就可以说S和T的编辑距离等于3了。
我们对最后一次的操作分析:
1.最后一次操作为copy。此时,根据题目的定义可知x[i]=y[j],我们待解决的问题就转化成了求将Xi-1转换为Yj-1的最小开销。将Xi-1转换为Yj-1的最优解一定包含在Xi转换为Yj的最优解内。用反证法证明:若存在从Xi-1到yj-1转换的更小的开销,那么用这个更小的开销来代替Xi-1转换为yj-1的最优解,这样就会得到一个更小的从Xi转换为Yj的开销,与已知的Xi转换为Yj的最优解矛盾,所以假设不成立。因此,当最后一次操作为copy时,可以定义c[i,j]=c[i-1,j-1]+cost(copy)。
2.最后一次操作为replace。此时,根据题目的定义可知x[i]≠y[j]。仿照上述分析,可以得到相同的最优子结构。此时c[i,j]=c[i-1,j-1]+cost(replace)。
3.最后一次操作为delete。根据题意,这时只是将x[i]从序列Xi中除去,对序列Yj没有任何影响,此时问题的最优子结构的形式为将Xi-1转换成Yj,于是可以得到c[i,j]=c[i-1,j]+cost(delete)。
4.最后一次操作为insert。根据题意,在进行插入操作时,序列Xi无任何变化,序列Yj添加一个字符,因此,这时候问题的最优子结构的形式为将Xi转换成为Yj-1,此时c[i,j]=c[i,j-1]+cost(insert)。
c语言代码(递归实现和动态规划实现):
// 动态规划实现 最小编辑距离 #include<stdio.h> #include<stdlib.h> #include<string.h> // 测试字符串 #define STRING_X "SUNDAY" #define STRING_Y "SATURDAY" #define SENTINEL (-1) #define EDIT_COST (1) inline int min(int a, int b) { return a < b ? a : b; } // Returns Minimum among a, b, c int Minimum(int a, int b, int c) { return min(min(a, b), c); } // Strings of size m and n are passed. // Construct the Table for X[0...m, m+1], Y[0...n, n+1] int EditDistanceDP(char X[], char Y[]) { // Cost of alignment int cost = 0; int leftCell, topCell, cornerCell; int m = strlen(X)+1; int n = strlen(Y)+1; // T[m][n] int *T = (int *)malloc(m * n * sizeof(int)); // Initialize table for(int i = 0; i < m; i++) for(int j = 0; j < n; j++) *(T + i * n + j) = SENTINEL; // Set up base cases // T[i][0] = i for(int i = 0; i < m; i++) *(T + i * n) = i; // T[0][j] = j for(int j = 0; j < n; j++) *(T + j) = j; // Build the T in top-down fashion for(int i = 1; i < m; i++) { for(int j = 1; j < n; j++) { // T[i][j-1] leftCell = *(T + i*n + j-1); leftCell += EDIT_COST; // deletion // T[i-1][j] topCell = *(T + (i-1)*n + j); topCell += EDIT_COST; // insertion // Top-left (corner) cell // T[i-1][j-1] cornerCell = *(T + (i-1)*n + (j-1) ); // edit[(i-1), (j-1)] = 0 if X[i] == Y[j], 1 otherwise cornerCell += (X[i-1] != Y[j-1]); // may be replace // Minimum cost of current cell // Fill in the next cell T[i][j] *(T + (i)*n + (j)) = Minimum(leftCell, topCell, cornerCell); } } // 结果存储在 T[m][n] cost = *(T + m*n - 1); free(T); return cost; } // 递归方法实现 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; // Recurse 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); } int main() { char X[] = STRING_X; // vertical char Y[] = STRING_Y; // horizontal printf("Minimum edits required to convert %s into %s is %d\n", X, Y, EditDistanceDP(X, Y) ); printf("Minimum edits required to convert %s into %s is %d by recursion\n", X, Y, EditDistanceRecursion(X, Y, strlen(X), strlen(Y))); return 0; }
以上代码转自点击打开链接
自己的代码:
<span style="font-size:18px;">#include <stdio.h> #include <stdlib.h> #include <string.h> int c[1005][1005]={0}; int min(int a,int b) { return (a>b)?b:a; } int same(char ch2,char ch1) { if(ch1==ch2) return 0; else return 1; } int main() { char a[1005],b[1005]; int lena,lenb,i,j,k; gets(a); gets(b); lena=strlen(a); lenb=strlen(b); for(i=0;i<=lena;i++) c[i][0]=i; for(j=0;j<=lenb;j++) c[0][j]=j; for(i=1;i<=lena;i++) { for(j=1;j<=lenb;j++) { c[i][j]=min(c[i-1][j-1]+<span style="color:#ff0000;">same(a[i-1],b[j-1])</span>,min(c[i-1][j]+1,c[i][j-1]+1)); } } printf("%d",c[lena][lenb]); return 0; } </span>