原题链接:Blue Jeans
题意:n组测试数据,魅族m行输入一个由ATGC组成的长为60的字符串,找最长公共子串,长度相同按字典序最小输出
思路:枚举第一个字符串的字串,判断是否与其它字符串匹配,取最长字典序最小的
#include <cstdio>
#include <cstring>
using namespace std;
char str[12][65];
char sub[65], ans[65];
int main(){
int T, n;
scanf("%d", &T);
while(T --){
scanf("%d", &n);
int i, j, k;
ans[0] = '\0'; //初始化答案为长度为0
for(i = 0;i < n;i ++)
scanf("%s", str[i]);
for(i = 1;i <= 60;i ++){ //枚举字串长度
int flag1 = 0;
for(j = 0;j < 60 - i + 1;j ++){ //枚举字串起始位置
int flag2 = 1;
int len = 0, t = j;
while(len < i){ //将str子串复制到sub
sub[len ++] = str[0][t ++];
}
sub[len] = '\0';
for(k = 1;k < n;k ++){ //枚举其他字符串
if(!strstr(str[k], sub)){ //判断是否含sub子串
flag2 = 0;
break;
}
}
if(flag2){ //都含有sub子串时
flag1 = 1;
if(strlen(ans) < strlen(sub)){ //取子串长度大的
strcpy(ans, sub);
}else if(strcmp(ans, sub) > 0){ //长度相同时,取字典序小的
strcpy(ans, sub);
}
}
}
if(!flag1) //没有长度为i的公共子串,当然也没有长度大于i的子串,跳出
break;
}
if(strlen(ans) < 3){
printf("no significant commonalities\n");
}else{
printf("%s\n", ans);
}
}
return 0;
}
kmp实现:
#include <cstdio>
#include <cstring>
using namespace std;
char str[12][65];
char sub[65], ans[65];
int next[1010];
void get_next(char t[], int next[]) { //获得next改进数组nextval数组
int lent = strlen(t);
next[0] = -1;
int k = -1, j = 0;
while (j < lent - 1)
{
//p[k]表示前缀,p[j]表示后缀
if (k == -1 || t[j] == t[k]) {
++j; ++k;
//较之前next数组求法,改动在下面4行
if (t[j] != t[k])
next[j] = k; //之前只有这一行
else
//因为不能出现t[j] = t[ next[j ]],所以当出现时需要继续递归,k = next[k] = next[next[k]]
next[j] = next[k];
}
else {
k = next[k];
}
}
}
int index_kmp(char s[], char t[]) {
get_next(t, next);
int i = 0, j = 0;
int lens = strlen(s), lent = strlen(t);
while (i < lens && j < lent) {
//①如果j = -1,或者当前字符匹配成功(即s[i] == t[j]),都令i++,j++
if (j == -1 || s[i] == t[j]) {
i++;j++;
}
else {//②如果j != -1,且当前字符匹配失败(即s[i] != t[j]),则令 i 不变,j = next[j]
//next[j]即为j所对应的next值
j = next[j];
}
}
if(j == lent)
return i - j;
else
return -1;
}
int main(){
int T, n;
scanf("%d", &T);
while(T --){
scanf("%d", &n);
int i, j, k;
ans[0] = '\0'; //初始化答案为长度为0
for(i = 0;i < n;i ++)
scanf("%s", str[i]);
for(i = 1;i <= 60;i ++){ //枚举字串长度
int flag1 = 0;
for(j = 0;j < 60 - i + 1;j ++){ //枚举字串起始位置
int flag2 = 1;
int len = 0, t = j;
while(len < i){ //将str子串复制到sub
sub[len ++] = str[0][t ++];
}
sub[len] = '\0';
for(k = 1;k < n;k ++){ //枚举其他字符串
if(index_kmp(str[k], sub) == -1){ //判断是否含sub子串
flag2 = 0;
break;
}
} if(flag2){ //都含有sub子串时
flag1 = 1;
if(strlen(ans) < strlen(sub)){ //取子串长度大的
strcpy(ans, sub);
}else if(strcmp(ans, sub) > 0){ //长度相同时,取字典序小的
strcpy(ans, sub);
}
}
}
if(!flag1) //没有长度为i的公共子串,当然也没有长度大于i的子串,跳出
break;
}
if(strlen(ans) < 3){
printf("no significant commonalities\n");
}else{
printf("%s\n", ans);
}
}
return 0;
}