题干
许多程序会大量使用字符串。对于不同的字符串,我们希望能够有办法判断其相似程序。我们定义一套操作方法来把两个不相同的字符串变得相同,具体的操作方法为:
- 修改一个字符(如把“a”替换为“b”);
- 增加一个字符(如把“abdd”变为“aebdd”);
- 删除一个字符(如把“travelling”变为“traveling”);
比如,对于“abcdefg”和“abcdef”两个字符串来说,我们认为可以通过增加/减少一个“g”的方式来达到目的。上面的两种方案,都仅需要一 次 。把这个操作所需要的次数定义为两个字符串的距离,而相似度等于“距离+1”的倒数。也就是说,“abcdefg”和“abcdef”的距离为1,相似度 为1/2=0.5。
给定任意两个字符串,你是否能写出一个算法来计算它们的相似度呢?
我的解题思路
- 如果两个字符串长度一样,那么只需要统计对应位置不一样的字符串的个数
- 如果两个字符串长度不一样,对长的为标准,逐一与短的比较,如果对应字符相同,则长的和短的都往后挪动一下,两者不同,则长的往后移动,短的不移动。
刚开始我以为我对了,直到找到了一种情况我是没有办法解决的,请看下面代码中的注释部分。
代码
#include <stdio.h>
#include <string.h>
float getStringSim(char *str1,char *str2){
int distance=getStringDistance(str1,str2);
return 1/(distance+1);
}
int getStringDistance(char *str1,char *str2){
int distance=0;
int length1=strlen(str1);
int length2=strlen(str2);
/*下面三句是防止有字符串为空的情况*/
if(length1==0&&length2==0) return 0;
if(length1==0) return length2;
if(length2==0) return length1;
char *longStr;
char *shortStr;
if(length1==length2){
longStr=str1;
shortStr=str2;
for(;*longStr!='\0';++longStr,++shortStr){
if(*longStr!=*shortStr) distance++;
}
return distance;
}else if(length1>length2){
longStr=str1;
shortStr=str2;
}else{
longStr=str2;
shortStr=str1;
}
//下面的代码只有字符串长度两者不相等才会执行
while(*longStr!='\0'){
if(*longStr==*shortStr){
longStr++;
shortStr++;
continue;
}
distance++;
longStr++;
}
return distance;
}
int main(int argc, char **argv) {
int distance;
distance=getStringDistance(" "," ");
printf(" 和 的距离:%d\n",distance);
distance=getStringDistance("aaa"," ");
printf("aaa和 的距离:%d\n",distance);
distance=getStringDistance(" ","aaa");
printf(" 和aaa的距离:%d\n",distance);
distance=getStringDistance("a","b");
printf("a和b的距离:%d\n",distance);
distance=getStringDistance("abcd","abcd");
printf("abcd和abcd的距离:%d\n",distance);
distance=getStringDistance("abcd","bcda");
printf("abcd和bcda的距离:%d\n",distance);
distance=getStringDistance("abcd","bd");
printf("abcd和bd的距离:%d\n",distance);
distance=getStringDistance("abdd","aebdd");
printf("abdd和aebdd的距离:%d\n",distance);
distance=getStringDistance("travelling","traveling");
printf("travelling和traveling的距离:%d\n",distance);
/*当以上测试用列全部正确的时候,我还以为天才般的我发现了什么
* 但是下面两个测试用列让我发现我忽略了一种情况
* 那就当第一个字母不同,但是第二个字母又相同的情况
*
* 想了一下,这个按我的思路没有办法解决的,
* 因为当第一个不一样的时候,我不知道是是缺少了一个还是替换第一个,
* 所以才造成了第一个无法处理
*/
distance=getStringDistance("kitten","sitting");
printf("kitten和sitting的距离:%d\n",distance);
distance=getStringDistance("abcd","zbd");
printf("abcd和zbd的距离:%d\n",distance);
}
运行结果
asd@asd-desktop:~/workspace/test/src$ ./a.out
和 的距离:0
aaa和 的距离:3
和aaa的距离:3
a和b的距离:1
abcd和abcd的距离:0
abcd和bcda的距离:4
abcd和zbd的距离:4 注意:错误
abdd和aebdd的距离:1
travelling和traveling的距离:1
kitten和sitting的距离:7 注意:错误
asd@asd-desktop:~/workspace/test/src$
进一步阅读
- 书后面的答案我认为很完美,因为我自己研究了一遍,所以很轻松就看懂了
- 算法导论有整整一章都在讲这个问题,可以参考
- 这篇博客讲的也不错,不过KMP算法还真是有点复杂哦 KMP字符串模式匹配详解