题目来源:
http://poj.org/problem?id=3080
分析:
题意:要求你求出每组字符串的最长公共子串,公共子串长度要求至少为3。
注意,当出现等长的公共字符串时,输出按字典序字符串最小的那个。若没公共子串,输出“no significant commonalities。
分析: 用kmp 枚举,让第一个字符串的长度大于等于3的子串分别与其他字符串匹配比较,第一个字符串的长度 从 len 开始向下减, 直到发现一个 公共字串,则为最大 公共字串。
代码如下:
const int Max_N = 65; char s[12][Max_N]; int next[Max_N]; //后缀数组(前缀函数) //数组从1开始 void get_next(int m, char * p){ char tmp[Max_N]; strcpy(tmp+1, p); int i,k=0; next[1]=0; for(i=2; i<=m ; i++){ while(k>0 && tmp[k+1] != tmp[i]) k=next[k]; if(tmp[k+1] == tmp[i]) k++; next[i]= k; } } // 匹配算法,t1为目标串,n为目标长度, p1为模式串, m为 模式长度 // 下标都从1开始 bool kmp(char * t1, char * p1,int n, int m){ char t[Max_N], p[Max_N]; strcpy(t+1,t1); strcpy(p+1,p1); int i,k=0; int cnt=0; for(i=1; i<=n; i++){ while(k>0 && p[k+1] != t[i]) k=next[k]; if(p[k+1] == t[i]) k++; if(k == m) return 1; } return 0; } int main(){ int t,j; scanf("%d",&t); while(t--){ int m; int flag = 0; char res[Max_N] = "no significant commonalities"; scanf("%d",&m); for(int i=0; i<m; i++) scanf("%s",s[i]); int len=strlen(s[0]); for(int l=len ; l>=3; l--){ // 枚举子串的长度从大到小 for(int pos = 0; pos + l <= len ; pos++){ // 枚举第一个字符串的位置从0到最大 get_next(l, s[0]+pos ); for( j=1; j<m; j++){ int n=strlen(s[j]); if( !kmp(s[j] , s[0]+ pos, n,l) ) break; } if(j == m ){ if(strcmp(res, s[0]+pos) > 0){ // 若长度相等,但从不同位置开始的,还需比较字典序最小 strcpy(res , s[0]+pos ); res[l] = '\0'; //使复制的到 l-1 处结束输出 ,这个地方 很关键 flag=1; } } } if(flag) break; } printf("%s\n",res); } return 0; }