View Code
const int maxn = 11111; //文本最大长度 int fail[maxn]; //失败了应该跳的位置 char str[maxn], text[maxn]; //输入文本和待匹配的字符串 //初始位置从0开始 void get_next(int n) { int i, j=-1; for(fail[0]=-1, i=1;i < n; i++) { while(j>=0 && str[i]!=str[j+1]) j=fail[j]; if(str[j+1]==str[i]) j++; fail[i]=j; } } int kmp(int n,int m) { //n:str长度 m:text长度 int i, j=-1, count=0; get_next(n); for(i = 0;i < n; i++) { while(j>=0 && text[i]!=str[j+1]) j=fail[j]; if(text[i]==str[j+1]) j++; if(j==m-1) { count++; // printf("%d\n", i-m+2); //存在的话打印输出匹配的开始位置 j = fail[j]; //保证程序继续进行 } } return count; }
kmp求一个字符串循环,if(n%(n-1-fail[n-1])==0) ans=n/(n-1-fail[n-1]);
View Code
//kmp求一个字符串循环,if(n%(n-1-fail[n-1])==0) ans=n/(n-1-fail[n-1]); /*****************************\ 必要性:存在最小循环节长度为k,有fail[n-1]=n-1-k;所以n%(n-1-fail[n-1])=0 \*****************************/ const int MM = 1111111; typedef __int64 int64; #define debug puts("wrong") int n; int fail[MM]; char str[MM]; void get_next(int n) { int i,j=-1; for(fail[0]=-1,i=1;i<n;i++) { while(j>=0 && str[i]!=str[j+1]) j=fail[j]; if(str[j+1]==str[i]) j++; fail[i]=j; } } void get_data() { int i,j,k; // scanf("%s", str); n=strlen(str); get_next(n); } void solve() { int i,j,k,ans=1, tmp=n-fail[n-1]-1; if(n%tmp==0) printf("%d\n",n/tmp); else printf("1\n"); } int main() { while(scanf("%s",str)!=EOF) { if(str[0]=='.') break; else get_data(),solve(); } return 0; }
拓展KMP
http://poj.org/problem?id=2752
View Code
//POJ2752 输出一个字符串的所有后缀与此字符串前缀完全匹配的长度 const int MM = 1111111; typedef __int64 int64; #define debug puts("wrong") int N,M; int fail[MM]; int next[MM], cnt, res[MM]; char str[MM], ch[MM]; /**************************************\ next[i]存的是str[i]的后缀suf[i]与ch的前缀 的最大匹配字符的个数 复杂度:O(N) \**************************************/ void get_extend_next(int n) { int i,j=0,k,len,l; while((j+1)<n && str[j]==str[j+1]) j++; fail[1]=j; for(k=1,i=2; i<n ;i++) { len=k+fail[k]-1, l=fail[i-k]; if(l<(len-i+1)) fail[i]=l; else { j=f_max(0,len-i+1); while((i+j)<n && str[i+j]==str[j]) j++; fail[i]=j, k=i; } } } void extend_kmp(int n,int m) { //n为模式串的长度 m为匹配串的长度 int i,j=0,k,len,l; while(j<n && j<m && ch[j]==str[j]) j++; next[0]=j; for(k=0,i=1; i<m ;i++) { len=k+next[k]-1,l=fail[i-k]; if(l<(len-i+1)) next[i]=l; else { j=f_max(0,len-i+1); while((i+j)<m && j<n && str[j]==ch[i+j]) j++; next[i]=j, k=i; } } } void solve() { int i,j,k,n,m; n=strlen(str); for(i=0;i<n;i++) ch[i]=str[i]; ch[n]='\0'; m=strlen(ch); get_extend_next(n); extend_kmp(n,m); cnt=0; for(i=n-1;i>=0;i--) if((n-i)==next[i]) res[cnt++]=n-i; printf("%d",res[0]); for(i=1;i<cnt;i++) printf(" %d",res[i]); printf("\n"); } int main() { while(scanf("%s",str)!=EOF) solve(); return 0; }