您的位置:首页 > 编程语言

编程之美系列之计算字符串的相似度

2013-09-13 11:32 323 查看
题目描述:也就是给一个源串和目标串,计算最少的操作数,使得源串进行下列操作之后等于目标串。

1、在给定的位置插入字符

2、将当前字符替换成任意字符

3、删除任意字符
题目分析

如果当前两个字符相等,则结果就是Src+1和Pattern+1两个字符串的最小操作数。

如果不等,就分三种情况:

1、如果是在给定的位置插入字符,那要求的操作数就是Src和Pattern+1两个字符串的最小操作数

2、如果将当前字符替换,那要求的操作数就是Src+1和Pattern+1两个字符串的最小操作数3、如果是删除Src的当前字符,则要求的操作数就是Src+1和Pattern两个字符串的最小操作数

最终结果就是上面三种情况中最小的操作数+1.
递归解法:程序很容易就可以写出来,递归的出口就是某一个字符串到达串尾,则距离就是没有到达串尾的那个字符串的长度。
非递归的解法:就是动态规划,假设dp[i][j]表示Src从第i个字符开始与Pattern从第j个字符开始所求得的最小操作数,动态规划递推的式子如下:

if Src[i] != Pattern[j], dp[i][j] = min(dp[i][j + 1], dp[i + 1][j + 1], dp[i +1][j];

else, dp[i][j] = dp[i + 1][j + 1];

使用动态规划需要注意的地方:

1、递推式中只出现了后面的数据,所以递推的时候应该是从后到前。

2、注意递推时的边界条件的处理。

核心参考代码如下:
//递归解法
int CalStr(const char* Src, const char *Pattern)
{
assert(Src && Pattern);
if(*Src == '\0')
{
return strlen(Pattern);
}
if(*Pattern == '\0')
{
return strlen(Src);
}
if(*Src == *Pattern)
{
return CalStr(Src + 1, Pattern + 1);
}
int t1 = CalStr(Src, Pattern + 1);//插入字符
int t2 = CalStr(Src + 1, Pattern + 1);//替换字符
int t3 = CalStr(Src + 1, Pattern);//删除字符
return min(t1, t2, t3) + 1;
}
//非递归解法,动态规划
int CalStrDP(const char *Src, const char *Pattern)
{
assert(Src && Pattern);
memset(dp, 0, sizeof(int) * Max_N * Max_N);
int nLen1 = strlen(Src);
int nLen2 = strlen(Pattern);
int i,j;
for(i = nLen1 - 1; i >= 0; --i)
{
for(j = nLen2 - 1; j >= 0; --j)
{
if(Src[i] == Pattern[j])
{
dp[i][j] = dp[i + 1][j + 1];
}
else
{
if(i < nLen1 - 1 || j < nLen2 - 1)//如果在两个字符串的末尾,则默认初始值为0,直接计算
{
if(i + 1 >= nLen1)//设置边界值
{
dp[i + 1][j + 1] = Max_N;
dp[i + 1][j] = Max_N;
}
if(j + 1 >= nLen2)//设置边界值
{
dp[i][j + 1] = Max_N;
dp[i + 1][j + 1] = Max_N;
}
}
dp[i][j] = min(dp[i][j + 1], dp[i + 1][j + 1], dp[i + 1][j]) + 1;
}
}
}
return dp[0][0];
}

下面给出main函数和辅助函数:

#include<stdio.h>
#include<string.h>
#include<assert.h>
const int Max_N = 100;
int dp[Max_N][Max_N];

inline int min(const int a, const int b, const int c)
{
int t = a < b ? a : b;
return t < c ? t : c;
}

int main()
{
char Src[Max_N];
char Pattern[Max_N];
while(gets(Src) && gets(Pattern))
{
printf("递归:%d\n", CalStr(Src, Pattern));
printf("非递归:%d\n", CalStrDP(Src, Pattern));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息