题意:找出所给串的最长公共子序列。
思路:以第一个从串为模板,二重for循环枚举第一个串的子串,然后以这个子串为模板串,用kmp匹配其他的串,当剩下的串中都包含有这个子串时,选取最长且字典序最小的串
#include <iostream>
#include <algorithm>
#include <cmath>
#include <ctype.h>
#include <cstring>
#include <cstdio>
#include <sstream>
#include <cstdlib>
#include <iomanip>
#include <string>
#include <queue>
#include <map>
using namespace std;
const int maxn=1e6+10;
int Next[100];
void getNext(char w[],int m)//递推next数组
{
int i=0,j=-1;
memset(Next,0,sizeof(Next));
Next[0]=-1;;
while(i<m)
{
if(j==-1||w[i]==w[j])
Next[++i]=++j;
else
{
j=Next[j];
}
}
}
bool kmp(char w[],int m,char s[],int n)//w模板串,m模板串长度,s目标串,n目标串长度
{
int i=0,j=0;
getNext(w,m);
while(i<n)
{
if(j==-1||w[j]==s[i])
i++,j++;
else
j=Next[j];
if(j>=m)
{
return true;
}
}
return false;
}
int main()
{
char ans[100];
char str[20][100];
int t;
scanf("%d",&t);
bool flag;
char w[100];
while(t--)
{
int i,j,n,k;
flag=false;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%s",str[i]);
int len=strlen(str[0]);
for(i=0;i<len;i++)
{
int cnt=0;
w[cnt++]=str[0][i];//枚举开头
for(j=i+1;j<len;j++)
{
w[cnt++]=str[0][j];//枚举结尾
for(k=1;k<n;k++)
{
if(!kmp(w,cnt,str[k],strlen(str[k])))//与剩下的串一一匹配
break;//有一个串不含有子串就退出
}
if(k>=n)//如果每个串都含有这个子串
{
if(!flag||cnt>strlen(ans))//如果是第一答案,或者比原来的串长,保存替换
{
w[cnt]='\0';
strcpy(ans,w);
flag=true;
}
else
{
w[cnt]='\0';
if(cnt==strlen(ans)&&strcmp(w,ans)<0)//如果长度相等保存字典序小的
strcpy(ans,w);
}
}
}
}
if(!flag||strlen(ans)<3)
{
printf("no significant commonalities\n");
continue;
}
printf("%s\n",ans);
}
return 0;
}