题意:有2到10个case,每个case里有n个长度都为60的串,求出它们的最长公共子串,如果这个子串的长度 < 3则输出“no significant commonalities”,如果存在多个最长公共子串,则输出字典序最小的那一个。
思路,KMP+枚举,从第0个串中,从长度为60开始,不断选取子串,与其他串做比较,假如在某长度发现了都匹配,压入结果,将同长度的子串按字典序排序,输出最小
- #include<iostream>
- #include<string>
- #include<vector>
- #define MAXSIZE 60 //输入比较的字符串长度
- using namespace std;
- void get_nextval(string T,int *nextval)
- {
- int i,j;
- i = 1;
- j = 0;
- nextval[1] = 0; //经常忘掉这一句
- while(i<T.size()-1)
- {
- if(j==0||T[i]==T[j])
- {
- ++i;
- ++j;
- if(T[i]!=T[j])
- {
- nextval[i] = j;
- }
- else
- {
- nextval[i] = nextval[j];
- }
- }
- else
- {
- j = nextval[j];
- }
- }
- }
- int Index_KMP(string S,string T,int pos)
- {
- int i = pos;
- int j = 1;
- int nextval[255];
- get_nextval(T,nextval);
- while(i<=S.size()-1&&j<=T.size()-1)
- {
- if(j==0||S[i] == T[j])
- {
- i++;
- j++;
- }
- else
- {
- j = nextval[j];
- }
- }
- if(j>T.size()-1)
- return i - T.size()+1;
- else
- return 0;
- }
- int main()
- {
- int cas,n;
- string head = "#";
- cin>>cas;
- vector<string> dna;
- vector<string> result;
- for(int i=0;i<cas;i++)
- {
- vector<string> dna;
- cin>>n;
- for(int j=0;j<n;j++)
- {
- string tmp;
- cin>>tmp;
- dna.push_back(head+tmp);
- }
- vector<string> result;
- for(int j=MAXSIZE;j>=3;j--) //j表示要从第一个串里取出子串的长度
- {
- for(int s = 1;s<MAXSIZE+2-j;s++) //s表示从第一个串里的第几个字符开始取这个子串
- {
- int flag2 = 1;
- string current = dna[0].substr(s,j);
- for(int l=1;l<dna.size();l++) //对剩下的各个字符串进行子串匹配
- {
- flag2 = Index_KMP(dna[l],head+current,1); //注意,第一个参数是主串,第二个参数是子串
- if(flag2==0) //假如碰到一个,不是其子串,直接break掉
- break;
- }
- if(flag2>0) //把所有其他字符串都比较过后,发现都是子串,把此结果压到 结果向量中
- result.push_back(current);
- }
- if(result.size()>0) //把同一个长度比完之后,假如已经有答案了,没必要去比较更小的子串,中断
- break;
- }
- if(result.size()==0)
- cout<<"no significant commonalities"<<endl;
- else
- {
- string small = result[0];
- for(int j=1;j<result.size();j++)
- {
- if(result[j]<small)
- small = result[j];
- }
- cout<<small<<endl;
- }
- }
- system("pause");
- }