算法题8 动态规划之字符串相似度

题目

  题目来源:《编程之美》

  把两个字符串变成相同的基本操作定义如下:

  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;
}

  

posted @ 2016-01-28 22:11  summerxx  阅读(458)  评论(0编辑  收藏  举报