题意:给m个长度不超过60的字符串,输出这些字符串共同的最长公共子串。(多组输入)当然,题目给的数据m<=10&&字符串长度不超过60,所以可以直接暴力做。这里只讲用KMP来写的解法。
题解:枚举第一个串的所有子串,然后用KMP算法去匹配这个子串和所有其它串看是否在其它串中都出现过,如果都出现过那肯定就是大家共同的公共子串。为了简单我们可以直接从最长的往短的遍历,这样第一个符合要求的一定就是最长的子串直接结束输出就行了。做法特别简单相当于是KMP的模板题。
附上代码:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
string s[15];
int next[100];
void get_next(string a, int next[])
{
int lena =a.size();
next[0] = -1;
int k = -1;
int j = 0;
while (j < lena - 1)
{
if(k == -1 || a[j] == a[k])//a[k]表示前缀,a[j]表示后缀
{
++j;
++k;
next[j]=k;
}
else
{
k = next[k];
}
}
}
int kmp(string a,string b)//a模式串,b匹配串
{
int lena=a.size();
int lenb=b.size();
int i=0;
int j=0;
while(i<lena&&j<lenb)
{
if(j==-1||a[i]==b[j])
{
i++;
j++;
}
else
{
j=next[j];
}
}
if(j==lenb)
return i-j;
return -1;
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
string ans="";//一定要定义在里面否则会wa
for(int i=1;i<=n;i++)
cin>>s[i];
int len1=s[1].size();
int l;
int bo,boo=0;
for(l=len1;l>=3;l--)//枚举字符串长度
{
bo=0;
for(int i=0;i<=len1-l;i++)//枚举起点终点
{
memset(next,0,sizeof(next));
string ss=s[1].substr(i,l);//记住这种操作,把一个字符串的一部分单独截出来
get_next(ss,next);
int flag=0;
for(int j=2;j<=n;j++)
{
if(kmp(s[j],ss)==-1)
{
flag=1;
break;
}
}
if(flag==0)
{
bo=1;
int len2=ans.size();
int len3=ss.size();
if(len2<len3)
ans=ss;
else if(len2==len3)
ans=min(ans,ss);
}
}
if(bo==1)
{
boo=1;
cout<<ans<<endl;
break;
}
}
if(boo==0)
printf("no significant commonalities\n");
}
return 0;
}