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

题目描述:也就是给一个源串和目标串,计算最少的操作数,使得源串进行下列操作之后等于目标串。
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;
}


你可能感兴趣的:(编程之美,动态规划)