扩展的KMP算法,这个算法作为KMP的扩展,可以说是包含KMP的。它求出了一组数值,extend[i]表示A串中以i开始的后缀(从i到lena的子串)与B串的最长公共前缀(从头数到不一样的字符)的长度,也就是LCP。next[i]表示T[i..m]与T的最长公共前缀长度,也就是自匹配的长度。设extend[0..k-1]已经算好,并且在以前的匹配过程中到达的最远位置是p-1。最远位置严格的说就是i+extend[i]-1的最大值,其中i=0,1,2,3,…,k-1;设取最大值的i是a。则有A[a~p-1] == B[0~p-a-1],可以推出有A[k~p-1] == B[k - a ~ p -1 - a] , 令L = next[k-a],若k+L<p,则extend[k]=L, 否则继续判断A[p]和B[p-k],直到不相等,这时需要更新extend[k]和a值。
http://acm.hdu.edu.cn/showproblem.php?pid=4333
void build_next() { int k, q, p, a; next[0] = len_t; for (k = 1, q = -1; k < len_t; k ++, q –) { if (q < 0 || k + next[k - a] >= p) { if (q < 0)q = 0, p = k; //q是B串继续向后匹配的指针,p是A串继续向后匹配的指针,也是曾经到达过的最远位置+1 //q在每次计算后会减小1,直观的讲就是B串向后错了一位 while (p < len_t && T[p] == T[q]) { p ++, q ++; } next[k] = q, a = k; } else { next[k] = next[k - a]; } } } void extend_KMP() { int k, q, p, a; for (k = 0, q = -1; k < len_s; k ++, q –) { if (q < 0 || k + next[k - a] >= p) { if (q < 0)q = 0, p = k; while (p < len_s && q < len_t && S[p] == T[q]) { p ++, q ++; } extend[k] = q, a = k; } else { extend[k] = next[k - a]; } } }
#include<iostream> #include<cstdio> #include<cstdlib> #include<ctime> #include<queue> #include<cstring> #include<set> #include<cmath> #include<algorithm> #define LL long long using namespace std; const int N=200005; char s[N]; int next[N];//next 指向的是以此点开始的字符串应该与原串中的哪个字符进行比较 // 当然比较的时候此串也要找对应的字符进行比较 如果超过字符串长度 说明相等 void getnext(int n) { int l=1,r=-1;//l 和 r 代表循环串的左右位置 next[0]=0; for(int i=1;i<n;++i) {//next[i]表示s与s[i..n]的最长公共前缀的长度 if(i+next[i-l]<=r) { next[i]=next[i-l];//如果前面对应的循环串对应位置字符要找的位置对应到本串中字符要找的位置没有超过r 说明可以直接将答案copy过来 }else { int j=max(r-i+1,0);//否则选择可以最靠后开始的位置进行依次比较 直到找到不同的 并记录循环串位置 for(;j+i<2*n;++j) if(s[j]!=s[i+j]) break; next[i]=j; l=i; r=i+j-1; } } } int main() { int T; //freopen("data.txt","r",stdin); scanf("%d",&T); getchar(); for(int c=1;c<=T;++c) { gets(s); int n=strlen(s); for(int i=0;i<n;++i) { s[i+n]=s[i]; } s[n*2]=0;//copy2 getnext(n); int i; for(i=1;i<n;++i) if(i+next[i]>=n) break;//找连续循环串位置 int m=(n%i)?m:i;//如果可以除进 则只要环内部分 int l=0,q=1,g=0; for(i=1;i<m;++i) { if(next[i]>=n) { ++q; } else if(s[next[i]]>s[i+next[i]]) { ++l; }else { ++g; } } printf("Case %d: %d %d %d\n",c,l,q,g); } return 0; }