字典树!我的做法是将前n-1个串分成若干子串(长度大于2),然后存入字典树,再将第n串也分成若干子串,进行匹配。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
int count;//记录子串的数目
int cur;//记录当前子串来自哪一原串(防止同一原串的相同子串重复记录)
node *next[26];
}memory[1000000],*root;
struct word
{
char s[65];
bool operator<(const word &t)const
{
return strcmp(s,t.s)<0;
}
}ans[60];//最长公共子串可能有多种,所以要多记录下来,然后按字典序排序
int ptr,n;
char str[65];
node *build_node()
{
node *p=&memory[ptr++];
for(int i=0;i<26;i++)
p->next[i]=NULL;
p->cur=-1;
p->count=0;
return p;
}
bool insert_tree(int s,int e,int id)
{
int index;
node *p=root;
for(int i=s;i<=e;i++)
{
index=str[i]-65;
if(p->next[index]==NULL)
p->next[index]=build_node();
p=p->next[index];
}
if(id!=p->cur)//该子串在当前串中没重复出现
{
p->cur=id;
p->count++;
if(p->count==n)
return true;
}
return false;
}
int main()
{
int cnt,t;
bool ok;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
ptr=0;
root=build_node();
for(int i=0;i<n-1;i++)//先将前n-1个串分别分成若干子串,然后存在字典树中
{
scanf("%s",str);
for(int j=0;j<60;j++)
for(int k=j+2;k<60;k++)
insert_tree(j,k,i);
}
ok=false;
scanf("%s",str);
cnt=0;
for(int len=60;len>2;len--)
{
if(ok)
break;
for(int i=0;i+len-1<60;i++)
if(insert_tree(i,i+len-1,n-1))
{
ok=true;
int j;
for(j=i;j<=i+len-1;j++)
ans[cnt].s[j-i]=str[j];
ans[cnt].s[j-i]='\0';
}
}
if(!ok)
{
printf("no significant commonalities\n");
continue;
}
sort(ans,ans+cnt);
printf("%s\n",ans[0].s);
}
return 0;
}