思路是二分长度(并没有太大的作用),然后kmp匹配,然后找出最大的串,如果有多个的话,要找出字典序最小的那个。
PS:这种找段落的,注意控制循环结束的条件。
#include "stdio.h"
#include "string.h"
#include "math.h"
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <algorithm>
#include <iostream>
using namespace std;
#define MAXM 1
#define MAXN 1
#define max(a,b) a > b ? a : b
#define min(a,b) a < b ? a : b
#define Mem(a,b) memset(a,b,sizeof(a))
int Mod = 1000000007;
double pi = acos(-1.0);
double eps = 1e-6;
char s[15][65];
char mod[65];
int nnext[65];
char ans[65];
//char ss[65];
//得到next
void getNext(int len)
{
int j = -1, i = 0;
nnext[0] = -1;
for(i = 0; i < len; ){
if( j == -1 || mod[i] == mod[j] ){
i ++, j ++;
if( mod[i] == mod[j] )
nnext[i] = nnext[j];
else
nnext[i] = j;
}
else
j = nnext[j];
}
}
//kmp
bool isMatch(int x, int len)
{
int len1 = strlen(s[x]);
for(int i = 0, j = 0; i < len1;){
if( j == -1){
i ++, j ++;
continue;
}
if( s[x][i] == mod[j] ){
i ++, j ++;
if( j == len )
return true;
}
else
j = nnext[j];
}
return false;
}
int T, N;
bool isOk(int len){
bool flag = false;
int ll = strlen(s[0]);
//i <= ll - len
for(int i = 0; i <= ll - len; i ++){
int j, k;
for(j = 0, k = 0; j < len; j ++, k ++){
mod[k] = s[0][i+j];
}
mod[k] = 0;
getNext(k);
for(j = 1; j < N; j ++){
if( !isMatch(j,k) )
break;
}
if( j == N ){
if( strlen(ans) != len || strcmp(ans, mod) > 0){
strcpy(ans, mod);
flag = true;
}
}
}
return flag;
}
void solve()
{
for(int i = 0; i < N; i ++){
getchar();
scanf("%s",s[i]);
}
strcpy(ans, "");
int l = 2, r = strlen(s[0]);
//二分长度
while( l <= r ){
int mid = ( l + r + 1 ) >> 1;
if( isOk(mid) ){
l = mid + 1;
}
else
r = mid - 1;
}
if( strlen(ans) < 3 ){
printf("no significant commonalities\n");
}
else{
printf("%s\n",ans);
}
}
int main()
{
// freopen("d:\\test.txt", "r", stdin);
while( cin>>T ){
while( T -- ){
cin>>N;
solve();
}
}
return 0;
}