计算字符串的相似度

计算字符串的相似度

提出问题

许多程序会大量使用字符串。对于不同的字符串,我们希望能够有办法判断其相似程度。我们定义了一套操作方法来把两个不相同的字符串变得相同,具体的操作方法为:

1.修改一个字符(如把“a”替换为“b”)。

2.增加一个字符(如把“abdd”变为“aebdd”)。

3.删除一个字符(如把“travelling”变为“traveling”)。

比如,对于“abcdefg”和“abcdef”两个字符串来说,我们认为可以通过增加/减少一个“g“的方式来达到目的。上面的两种方案,都仅需要一次操作。把这个操作所需要的次数定义为两个字符串的距离,给定任意两个字符串,你是否能写出一个算法来计算出它们的距离?

分析与解法

不难看出,两个字符串的距离肯定不超过它们的长度之和(我们可以通过删除操作把两个串都转化为空串)。虽然这个结论对结果没有帮助,但至少可以知道,任意两个字符串的距离都是有限的。

我们还是应该集中考虑如何才能把这个问题转化成规模较小的同样的问题。如果有两个串A=xabcdae和B=xfdfa,它们的第一个字符是相同的,只要计算A[2,…,7]=abcdae和B[2,…,5]=fdfa的距离就可以了。但是如果两个串的第一个字符不相同,那么可以进行如下的操作(lenA和lenB分别是A串和B串的长度):

1.删除A串的第一个字符,然后计算A[2,…,lenA]和B[1,…,lenB]的距离。

2.删除B串的第一个字符,然后计算A[1,…,lenA]和B[2,…,lenB]的距离。

3.修改A串的第一个字符为B串的第一个字符,然后计算A[2,…,lenA]和B[2,…,lenB]的距离。

4.修改B串的第一个字符为A串的第一个字符,然后计算A[2,…,lenA]和B[2,…,lenB]的距离。

5.增加B串的第一个字符到A串的第一个字符之前,然后计算A[1,…,lenA]和B[2,…,lenB]的距离。

6.增加A串的第一个字符到B串的第一个字符之前,然后计算A[2,…,lenA]和B[1,…,lenB]的距离。

在这个题目中,我们并不在乎两个字符串变得相等之后的字符串是怎样的。所以,可以将上面6个操作合并为:

1.一步操作之后,再将A[2,…,lenA]和B[1,…,lenB]变成相同字符串。

2.一步操作之后,再将A[1,…,lenA]和B[2,…,lenB]变成相同字符串。

3.一步操作之后,再将A[2,…,lenA]和B[2,…,lenB]变成相同字符串。

这样,很快就可以完成一个递归程序。

递归解法:

#include<iostream>
#include<string>
#include<algorithm>

using namespace std;

int MinValue(int a,int b,int c)
{
	int min=a;
	if(b<min)
		min=b;
	if(c<min)
		min=c;
	return min;
}

int Distance(string strA,int pABegin,int pAEnd,
						string strB,int pBBegin,int pBEnd)
{
	if(pABegin>pAEnd)
	{
		if(pBBegin>pBEnd)
			return 0;
		else
			return pBEnd-pABegin+1;
	}
	if(pBBegin>pBEnd)
	{
		if(pABegin>pAEnd)
			return 0;
		else
			return pAEnd-pABegin+1;
	}
	if(strA[pABegin]==strB[pBBegin])
		return Distance(strA,pABegin+1,pAEnd,strB,pBBegin+1,pBEnd);
	else
	{
		int t1=Distance(strA,pABegin+1,pAEnd,strB,pBBegin,pBEnd);
		int t2=Distance(strA,pABegin,pAEnd,strB,pBBegin+1,pBEnd);
		int t3=Distance(strA,pABegin+1,pAEnd,strB,pBBegin+1,pBEnd);
		return MinValue(t1,t2,t3)+1;
	}
}

int main(int argc,char *argv[])
{
	string strA,strB;
	cin>>strA;
	cin>>strB;
	int ans=Distance(strA,0,strA.length()-1,strB,0,strB.length()-1);
	cout<<ans<<endl;
}

有什么地方需要改进的呢?问题在于:在递归的过程中,有些数据被重复计算了。

为了避免重复计算,我们可以将计算后的结果存储起来。

如下表所示

 j
 C(i-1,j-1)  C(i-1,j)
 i  C(i,j-1)  C(i,j)

我们注意到,当我们要计算distance(A[1,i],B[1,j])时,该值仅与红色部分的值相关。因此,我们只需要保存这些值即可。

所以动态规划是个很好地选择;

动态规划法:

#include<iostream>
#include<string>
#include<algorithm>
#define MAX 1000

using namespace std;

int dp[MAX][MAX];

int MinValue(int a,int b,int c)
{
	int min=a;
	if(b<min)
		min=b;
	if(c<min)
		min=c;
	return min;
}

int Distance(string strA,string strB)
{
	int i,j;
	int lenA=strA.length()+1;
	int lenB=strB.length()+1;
	for(i=0;i<lenA;i++)
		dp[i][0]=i;
	for(j=0;j<lenB;j++)
		dp[0][j]=j;
	dp[0][0]=0;
	for(i=1;i<lenA;i++)
	{
		for(j=1;j<lenB;j++)
		{
			if(strA[i-1]==strB[j-1])
				dp[i][j]=dp[i-1][j-1];
			else
				dp[i][j]=MinValue(dp[i][j-1],dp[i-1][j],dp[i-1][j-1])+1;
		}
	}
	return dp[lenA-1][lenB-1];
}

int main(int argc,char *argv[])
{
	string strA,strB;
	cin>>strA;
	cin>>strB;
	int ans=Distance(strA,strB);
	cout<<ans<<endl;
}

与动态规划类似的备忘录法:

#include<iostream>
#include<string>
#include<algorithm>
#define MAX 1000

using namespace std;

int dis[MAX][MAX];

int MinValue(int a,int b,int c)
{
	int min=a;
	if(b<min)
		min=b;
	if(c<min)
		min=c;
	return min;
}

int Distance(string strA,int pABegin,int pAEnd,
						string strB,int pBBegin,int pBEnd)
{
	if(dis[pABegin][pBBegin]>=0)
		return dis[pABegin][pBBegin];
	if(pABegin>pAEnd)
	{
		if(pBBegin>pBEnd)
			dis[pABegin][pBBegin]=0;
		else
			dis[pABegin][pBBegin]=pBEnd-pABegin+1;
		return dis[pABegin][pBBegin];
	}
	if(pBBegin>pBEnd)
	{
		if(pABegin>pAEnd)
			dis[pABegin][pBBegin]=0;
		else
			dis[pABegin][pBBegin]=pAEnd-pABegin+1;
		return dis[pABegin][pBBegin];
	}
	if(strA[pABegin]==strB[pBBegin])
	{
		dis[pABegin][pBBegin]=Distance(strA,pABegin+1,pAEnd,
		                                         strB,pBBegin+1,pBEnd);
		return dis[pABegin][pBBegin];
	}
	else
	{
		int t1=Distance(strA,pABegin+1,pAEnd,strB,pBBegin,pBEnd);
		int t2=Distance(strA,pABegin,pAEnd,strB,pBBegin+1,pBEnd);
		int t3=Distance(strA,pABegin+1,pAEnd,strB,pBBegin+1,pBEnd);
		dis[pABegin][pBBegin]=MinValue(t1,t2,t3)+1;
		return dis[pABegin][pBBegin];
	}
}

int main(int argc,char *argv[])
{
	int i,j;
	string strA,strB;
	cin>>strA;
	cin>>strB;
	for(i=0;i<MAX;i++)
		for(j=0;j<MAX;j++)
			dis[i][j]=-1;
	int ans=Distance(strA,0,strA.length()-1,strB,0,strB.length()-1);
	cout<<ans<<endl;
}

计算字符串的相似度

时间: 2024-08-04 12:48:25

计算字符串的相似度的相关文章

[华为]计算字符串的相似度

链接:https://www.nowcoder.com/questionTerminal/f549ee08ddd84b8485a4fa9aefaf4a38来源:牛客网 对于不同的字符串,我们希望能有办法判断相似程度,我们定义了一套操作方法来把两个不相同的字符串变得相同,具体的操作方法如下: 1 修改一个字符,如把"a"替换为"b". 2 增加一个字符,如把"abdd"变为"aebdd". 3 删除一个字符,如把"tr

华为机试-计算字符串的相似度

题目描述 对于不同的字符串,我们希望能有办法判断相似程度,我们定义了一套操作方法来把两个不相同的字符串变得相同,具体的操作方法如下: 1 修改一个字符,如把"a"替换为"b". 2 增加一个字符,如把"abdd"变为"aebdd". 3 删除一个字符,如把"travelling"变为"traveling". 比如,对于"abcdefg"和"abcdef&qu

第3章 结构之法——计算字符串的相似度

计算字符串的相似度 问题描述 分析与解法 具体代码如下: 1 package chapter3jiegouzhifa.StringSimilarity; 2 /** 3 * 计算字符串的相似度 4 * [解法一] 5 * @author DELL 6 * 7 */ 8 public class StringSimilarity { 9 public static int CalculateStringDistance(String str1, int b1, int e1, String str

编程之美3.3—计算字符串的相似度

题目: 许多程序会大量使用字符串.对于不同的字符串,我们希望能够有办法判断其相似程序.我们定义一套操作方法来把两个不相同的字符串变得相同,具体的操作方法为: 1.修改一个字符(如把"a"替换为"b"); 2.增加一个字符(如把"abdd"变为"aebdd"); 3.删除一个字符(如把"travelling"变为"traveling"); 比如,对于"abcdefg"和

Levenshtein Distance莱文斯坦距离算法来计算字符串的相似度

转 理解起来不难,但是很实用. 核心公式就是下面:             (1) 1.百度百科介绍: Levenshtein 距离,又称编辑距离,指的是两个字符串之间,由一个转换成另一个所需的最少编辑操作次数. 许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符. 编辑距离的算法是首先由俄国科学家Levenshtein提出的,故又叫Levenshtein Distance. 2.用途 模糊查询 3.实现过程 a.首先是有两个字符串,这里写一个简单的 abc和abe b.将

Levenshtein计算字符串的相似度

static void Main(string[] args) { Levenshtein(@"今天天气不错", @"今天的天气不错啊"); Console.Read(); } /// <summary> /// 字符串相似度计算 /// </summary> /// <param name="str1"></param> /// <param name="str2">

3.3 计算字符串的相似度

题目: 定义一套操作方法来把两个不相同的字符串变得相同,具体的操作方法为: 1.修改一个字符(如把"a"替换为"b"); 2.增加一个字符(如把"abdd"变为"aebdd"); 3.删除一个字符(如把"travelling"变为"traveling"); 给定任意两个字符串,你是否能写出一个算法来计算它们的距离呢? 方法: 不难看出,两个字符串的距离肯定不超过它们的长度之和(我们可以通

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

对于不同的字符串,判断其相似程度.可以修改一个字符,增加一个字符,删除一个字符等操作. 分析:当两个字符串第一个字符相等时,直接把两个字符串跳到第二个位置开始比较就可以了.当两个字符串第一个字符不相等时,不管怎么操作总是,要么第一个串跳到第二个位置,第二个串位置不变:或者第一个串位置不变,第二个跳到第二个位置:或者两个串都跳到第二个位置(同过修改串的字符).于是就可以写个递归程序处理. 1 int calculateStringDistance(string strA, int pABegin,

【华为OJ】【083-计算字符串的相似度】

[华为OJ][算法总篇章] [华为OJ][083-计算字符串的相似度] [工程下载] 题目描述 对于不同的字符串,我们希望能有办法判断相似程度,我们定义了一套操作方法来把两个不相同的字符串变得相同,具体的操作方法如下: 1 修改一个字符,如把"a"替换为"b". 2 增加一个字符,如把"abdd"变为"aebdd". 3 删除一个字符,如把"travelling"变为"traveling"