lcs 最长公共字串算法

  在“LD算法”中介绍了基于编辑距离的文本比较算法——LD算法。

  本文介绍基于最长公共子串的文本比较算法——Needleman/Wunsch算法。

  还是以实例说明:字符串A=kitten,字符串B=sitting

  那他们的最长公共子串为ittn(注:最长公共子串不需要连续出现,但一定是出现的顺序一致),最长公共子串长度为4。

  

  定义:

  LCS(A,B)表示字符串A和字符串B的最长公共子串的长度。很显然,LSC(A,B)=0表示两个字符串没有公共部分。

  Rev(A)表示反转字符串A

  Len(A)表示字符串A的长度

  A+B表示连接字符串A和字符串B

  性质:

  LCS(A,A)=Len(A)

  LCS(A,"")=0

  LCS(A,B)=LCS(B,A)

  0≤LCS(A,B)≤Min(Len(A),Len(B))

  LCS(A,B)=LCS(Rev(A),Rev(B))

  LCS(A+C,B+C)=LCS(A,B)+Len(C)

  LCS(A+B,A+C)=Len(A)+LCS(B,C)

  LCS(A,B)≥LCS(A,C)+LCS(B,C)

  LCS(A+C,B)≥LCS(A,B)+LCS(B,C)

  为了讲解计算LCS(A,B),特给予以下几个定义

  A=a1a2……aN,表示A是由a1a2……aN这N个字符组成,Len(A)=N

  B=b1b2……bM,表示B是由b1b2……bM这M个字符组成,Len(B)=M

  定义LCS(i,j)=LCS(a1a2……ai,b1b2……bj),其中0≤i≤N,0≤j≤M

  故:  LCS(N,M)=LCS(A,B)

      LCS(0,0)=0

      LCS(0,j)=0

      LCS(i,0)=0

  对于1≤i≤N,1≤j≤M,有公式一

  若ai=bj,则LCS(i,j)=LCS(i-1,j-1)+1

  若ai≠bj,则LCS(i,j)=Max(LCS(i-1,j-1),LCS(i-1,j),LCS(i,j-1))

  计算LCS(A,B)的算法有很多,下面介绍的Needleman/Wunsch算法是其中的一种。和LD算法类似,Needleman/Wunsch算法用的都是动态规划的思想。在Needleman/Wunsch算法中还设定了一个权值,用以区分三种操作(插入、删除、更改)的优先级。在下面的算法中,认为三种操作的优先级都一样。故权值默认为1。

  

  举例说明:A=GGATCGA,B=GAATTCAGTTA,计算LCS(A,B)

  第一步:初始化LCS矩阵

Needleman/Wunsch算法矩阵
G A A T T C A G T T A
000000000000
G0
G0
A0
T0
C0
G0
A0

  第二步:利用公式一,计算矩阵的第一行

Needleman/Wunsch算法矩阵
G A A T T C A G T T A
000000000000
G011111111111
G0
A0
T0
C0
G0
A0

  第三步:利用公式一,计算矩阵的其余各行

Needleman/Wunsch算法矩阵
G A A T T C A G T T A
000000000000
G011111111111
G011111112222
A012222222222
T012233333333
C012233444444
G012233345555
A012333345556

  则,LCS(A,B)=LCS(7,11)=6

  可以看出,Needleman/Wunsch算法实际上和LD算法是非常接近的。故他们的时间复杂度和空间复杂度也一样。时间复杂度为O(MN),空间复杂度为O(MN)。空间复杂度经过优化,可以优化到O(M)。

LCS算法的代码如下:

#include <iostream>
using namespace std;
void swp(string &str1, string &str2)
{
	string tmp = str1;
	str1 = str2;
	str2 = str1;
}
string lcs(string &str1, string &str2)
{
	if(str1.size() > str2.size())
	{
		swp(str1, str2);
	}
	int min_size = str1.size();
	int *lcs_arr = new int[min_size+1];
	for(int i = 0; i <= min_size; i++)
	{
		lcs_arr[i] = 0;
	}
	int str1_len = str1.size();
	int str2_len = str2.size();
	int lcs_max = 0;
	int pointer = 0;
	for(int i = 0; i< str2_len;i++)
	{
		for(int j = str1_len -1 ;j>=0; j--)
		{
			if(str1[j] == str2[i])
			{
				lcs_arr[j+1] = lcs_arr[j] + 1;
			}
			else
			{
				lcs_arr[j+1] = 0;
			}
			if(lcs_arr[j+1] > lcs_max)
			{
				lcs_max = lcs_arr[j+1];
				pointer = j;
			}
		}
	}
	delete [] lcs_arr;
	string tmp ;
	for(int k = pointer - lcs_max;k <= pointer; k++)
	{
		tmp += str1[k];
	}
	return tmp;
}
int main()
{
	string a ;
	string b ;
    cout<<"please input 2 lcs string"<<endl;
	cout<<"please input a"<<endl;
	cin>>a;
	cout<<"please input b"<<endl;
	cin>>b;
	cout<<"lcs is "<<lcs(a,b)<<endl;;
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值