题目
题目来源:《编程之美》
把两个字符串变成相同的基本操作定义如下:
1. 修改一个字符(如把 a 变成 b)
2. 增加一个字符 (如 abed 变成 abedd)
3. 删除一个字符(如 jeddon 变成 jedon)
针对于 jeddon到jedon 只需要删除一个或增加一个 d 就可以把两个字符串变为相同。把这种操作需要的次数定义为两个字符串的距离 L, 则相似度定义为1/(L+1) 即距离加一的倒数。那么jeddon和jedon的相似度为 1/1+1=1/2=0.5 也就是所两个字符串的相似度是 0.5。
给定任意两个字符串,你是否写出一个是否来计算出它们的相识度。
分析
这是一个多阶段决策问题,每个阶段的决策都和前面子问题的最优决策相关,可以用动态规划来做。
对于字符串str1 和str2,长度分别为m,n,设d[i,j]为str1的第[1—i]字符和str2的第[1—j]个字符之间的距离,
如果str1[i]=str2[j],则d[i,j]=d[i-1,j-1];
如果str1[i]和str2[j]替换一个字符,str1[0-i]和str2[0-j]就相同,比如"student"和"studens",则d[i,j]=d[i-1,j-1]+1;
如果str1[i]增加一个字符,str1[0-i]和str2[0-j]就相同,比如"student"和"students",则d[i,j]=d[i,j-1]+1;
如果str1[i]删除一个字符,str1[0-i]和str2[0-j]就相同,比如"students"和"student",则d[i,j]=d[i-1,j]+1;
由此可以得到关系式:
d[i,0]=i
d[0,j]=j;
d[i,j]=min{d[i-1,j-1]+1,d[i,j-1]+1,d[i-1,j]+1}
算法时间复杂度为O(m*n),空间复杂度为O(m*n)
代码
int SimilarityDegreeOfStrs(char* str1,char* str2) { int len1=strlen(str1); int len2=strlen(str2); int **d=new int*[len1+1]; for (int i=0;i<=len1;i++) { d[i]=new int[len2+1](); } for (int i=0;i<=len1;i++) { d[i][0]=i; } for (int j=0;j<=len2;j++) { d[0][j]=j; } for (int i=1;i<=len1;i++) { for (int j=1;j<=len2;j++) { if (str1[i-1]==str2[j-1]) { d[i][j]=d[i-1][j-1]; }else { int repl=d[i-1][j-1]+1; int add=d[i][j-1]+1; int del=d[i-1][j]+1; d[i][j]=MIN(MIN(repl,add),del); } } } int similarity=d[len1][len2]/(d[len1][len2]+1); //free for (int i=0;i<=len1;i++) { delete[] d[i]; } delete[] d; return similarity; }