最长公共子串问题

最长公共子串问题,较为常见的思路是动态规划吧,至于后缀数组等更高效的算法,本人菜鸟一个,理解能力有限啊。直接上解决思路。

问题解决思路:给定两个字符串s,t,求s,t的最长公共子串。假设最长公共子串的确包括s[i],t[j],并假设lcs[i,j]表示以字符串s的第i个字符,t的第j个字符结尾并包含s[i],t[j]的最长公共子串的长度,那么,就有如下的DP方程:

根据上述方程,就很容易写出最长公共子串的代码了。同时,为了输出最后最长公共子串,程序中可记录最长公共子串的位置,这样就得到结果了。该代码时间复杂度和空间复杂都是O(nm),n,m分别是s,t的长度。当然,空间复杂度可以更低。DP的话,解决该问题的时间复杂度就是0(nm)。后缀数组能够降低时间复杂度,好像可以到线性的时间复杂度。留着日后有时间再慢慢研究后缀数组的解法吧。

 

<span style="font-size:18px;">#include<iostream>
using namespace std;
int LCSubstr(const char *s,int sLen,const char*t,int tLen)
{
	if(NULL==s||NULL==t)
	{
		cout<<"Empty str"<<endl;
		return 0;
	}
	int **lcs;
	lcs = new int*[sLen];
	for(int i=0;i<sLen;i++)
		lcs[i]=new int[tLen];
	lcs[0][0]=0;
	for(int i=0;i<sLen;i++)
	{
		if(s[i]==t[0])
			lcs[i][0]=1;
		else
			lcs[i][0]=0;
	}
	for(int j=0;j<tLen;j++)
	{
		if(s[0]==t[j])
			lcs[0][j]=1;
		else
			lcs[0][j]=0;
	}
	int maxLen;
	int idx=-1;
	maxLen=s[0]==t[0]?1:0;
	for(int i=1;i<sLen;i++)
	{
		for(int j=1;j<tLen;j++)
		{
			if(s[i]==t[j])
			{
				lcs[i][j]=lcs[i-1][j-1]+1;
				if(lcs[i][j]>maxLen)
				{
					maxLen = lcs[i][j];
					idx = j;
				}
			}
			else
			{
				lcs[i][j]=0;
			}
		}
	}
	for(int i=0;i<sLen;i++)
	{
		for(int j=0;j<tLen;j++)
			cout<<lcs[i][j]<<"  ";
		cout<<endl;
	}
	//输出最长公共子串
	cout<<s<<"和"<<t<<"最长公共子串是:"<<endl;
	if(idx==-1)
	{
		cout<<"";
	}
	else
	{
		for(int i=idx-maxLen+1;i<=idx;i++)
			cout<<t[i];
	}
	cout<<endl;
	for(int i=0;i<sLen;i++)
		delete[] lcs[i];
	delete []lcs;
	return maxLen;
}
int main()
{
	char *s="adcdef";
	char *t="df";
	int sLen=strlen(s);
	int tLen=strlen(t);
	int x =LCSubstr(s,sLen,t,tLen);
	cout<<"最长公共字串长度是:"<<x<<endl;
	return 0;
}</span>

注:若两个字符串存在多个长度一样的最长公共子串,本程序只能返回其中一个,不能都返回。解决方案是:可再遍历以LCS矩阵,对其中多个最大的相同数字,从该位置起,按斜对线往左上方输出,直到遇到LCS的元素为0为止。有什么更好的办法,请指出来啊。
测试过一些用例,能至少通过题目所给出的所有用例,但不知源代码中是否仍然存在bug,或者这个思路完全有问题,欢迎指正哈。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值