HDOJ(1238) KMP
Substrings
http://acm.hdu.edu.cn/showproblem.php?pid=1238
先找到长度最短的字符串,把它的子串和该子串的逆序(按长度从大到小)依次与其他字符串匹配。
如果某个子串或它的逆序(如:“ro” ,”or“)和其他字符串都匹配,就返回此时的长度。
#include<iostream> #include<cstdio> #include<string> #include<vector> #include<algorithm> using namespace std; //下标以0开始的KMP void get_next(string b, int *next) { int i=0; int j=-1; next[i]=-1; int len_b=b.size(); while(i<len_b-1) { if(j==-1||b[i]==b[j]) { ++i; ++j; if(b[i]!=b[j]) next[i]=j; else next[i]=next[j]; } else { j = next[j]; } } } int KMP(string a,string b) { int i=0; int j=0; int len_a=a.size(); int len_b=b.size(); int next[101]; get_next(b,next); while(i<len_a&&j<len_b) { if(j==-1||a[i]==b[j]) { ++i; ++j; } else { j=next[j]; } } if(j>=len_b) return 1; else return 0; } int solve(vector<string> str,int mini) { string sub1,sub2; int i,j,k,m,res=0; int len=str[mini].size(); for(i=len;i>=1;i--) { for(j=0;i+j<=len;j++) { sub1=str[mini].substr(j,i); //选取str[mini]中以j开头长度为i的字串 sub2=sub1; reverse(sub2.begin(),sub2.end());//逆置字符串 int l=str.size(); for(k=0;k<l;k++) { string s=str[k]; if(KMP(s,sub1)==0&&KMP(s,sub2)==0) { break; } } if(k>=l) { res=i; goto A; } } } A: return res; } int main() { int t,n,i,mini; vector<string> str; string s; scanf("%d",&t); while(t--) { str.clear(); scanf("%d",&n); for(i=0;i<n;i++) { cin>>s; str.push_back(s); } mini=0; int len=str.size(); for(i=1;i<len;i++) { if(str[i].size()<str[mini].size()) { mini=i; } } printf("%d\n",solve(str,mini)); } return 0; }
KMP模板
下标以0开始
void get_next(string b, int *next) { int i=0; int j=-1; next[i]=-1; int len_b=b.size(); while(i<len_b-1) { if(j==-1||b[i]==b[j]) { ++i; ++j; if(b[i]!=b[j]) next[i]=j; else next[i]=next[j]; } else { j = next[j]; } } } int KMP(string a,string b) { int i=0; int j=0; int len_a=a.size(); int len_b=b.size(); int next[101]; get_next(b,next); while(i<len_a&&j<len_b) { if(j==-1||a[i]==b[j]) { ++i; ++j; } else { j=next[j]; } } if(j>=len_b) return i-len_b; else return 0; }
下标从1开始
void get_next(char *b,int *next) { int i=1; int j=0; next[1]= 0; int len_b=strlen(b)-1; //下标从1开始,子串的长度=strlen(b)-1 while(i<len_b) { if(j==0||b[i]==b[j]) //b[i]表示后缀的单个字符 { //b[j]表示前缀的单个字符 ++i; ++j; if (b[i]!=b[j]) next[i]=j; else next[i]=next[j]; } else j=next[j]; //若字符不相同,则j值回溯 } } int KMP(char *a,char *b,int pos) { int i=pos; //i用于主串a当前位置下标值 //若pos不为1,则从pos开始 int j=1; //j用于字串b当前位置下标值 int len_a=strlen(a)-1; int len_b=strlen(b)-1; int next[101]; get_next(b,next); //对字串b分析,得到next数组 while(i<=len_a&&j<=len_b) { if(j==0||a[i]==b[j]) { ++i; ++j; } else { j=next[j]; } } if(j>len_b) return i-len_b; else return 0; }
下标以1开始的next数组,实际上,是下标以0开始的next数组的值+1。KMP算法最重要的是得到子串的next[]。