题意:给出1-10个长度为60的字符串,求出最长的公共子串(长度不能小于3),如果有多个一样长的,输出字典序最短的。
解法:想到kmp时,自己第一反应枚举第一个串的所有子串,在其他所有串中走一遍kmp,复杂度为10*60*60*60,但是发现只需枚举第一个串后缀就可以,每次枚举记录在所有串能走最远中走的最短的那个长度。这样复杂度就成了10*60*60,0ms AC。
代码:
/**************************************************** * author:xiefubao *******************************************************/ #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <vector> #include <algorithm> #include <cmath> #include <map> #include <set> #include <stack> #include <string.h> using namespace std; #define eps 1e-8 typedef long long LL; char str[10][61]; int n; char ans[61]; char tool[61]; int out=0; char Next[61]; void getnext() { int i=0; int j=Next[0]=-1; int len=strlen(tool); while(i<len) { while(j!=-1&&tool[i]!=tool[j]) j=Next[j]; Next[++i]=++j; } } int kmp(int k) { int i=0,j=0; int res=0; for(int i=0; i<60; i++) { while(j!=-1&&str[k][i]!=tool[j]) j=Next[j]; j++; res=max(res,j); } return res; } int main() { int t; cin>>t; while(t--) { scanf("%d",&n); memset(ans,0,sizeof ans); memset(tool,0,sizeof tool); out=0; for(int i=0; i<n; i++) scanf("%s",str[i]); int len=strlen(str[0]); for(int i=0; i<len; i++) { memset(tool,0,sizeof tool); strncpy(tool,str[0]+i,len-i); int ma=60; getnext(); for(int j=1; j<n; j++) ma=min(ma,kmp(j)); if(ma>out) { out=ma; strncpy(ans,tool,out); ans[out]=0; } else if(ma==out) { if(strcmp(ans,tool)>0) strncpy(ans,tool,out); ans[out]=0; } } if(strlen(ans)<3)printf("no significant commonalities\n"); else printf("%s\n",ans); } return 0; }
poj3080(Blue Jeans)kmp求多个串公共子串,布布扣,bubuko.com
poj3080(Blue Jeans)kmp求多个串公共子串
原文:http://blog.csdn.net/xiefubao/article/details/25125039