轉自:https://blog.csdn.net/hao_zong_yin/article/details/77455285
KMP最小循環節、循環週期:
定理:
假設S的長度爲len,則S存在最小循環節,循環節的長度L爲len-next[len],子串爲S[0…len-next[len]-1]。
(1)如果len可以被len - next[len]整除,則表明字符串S可以完全由循環節循環組成。循環週期T=len/L。
(2)如果不能,說明還需要再添加幾個字母才能補全。需要補的個數是循環個數L-len%L=L-(len-L)%L=L-next[len]%L,L=len-next[len]。
理解:
對於一個字符串,如abcd abcd abcd,由長度爲4的字符串abcd重複3次得到,那麼必然有原字符串的前八位等於後八位。也就是說,對於某個字符串S,長度爲len,由長度爲L的字符串s重複R次得到,當R≥2時必然有S[0…len-L-1]=S[L…len-1],字符串下標從0開始。那麼對於KMP算法來說,就有next[len]=len-L。此時L肯定已經是最小的了(因爲next的值是前綴和後綴相等的最大長度,即len-L是最大的,那麼在len已經確定的情況下,L是最小的)。
模板例題:Cyclic Nacklace
代碼:
//另外字符串S完全由循環節循環組成時,擴展kmp也可以求出最小循環節的長度及出現的次數:在原串後面再接一個本身(不加原串的最後一個字符),它的每一個後綴與原串的最長公共前綴長度=原串長度的次數就是最小循環節出現的次數
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <stack>
using namespace std;
const int manx=1e5+10;
char p[manx];
int net[manx],lp;
void getnext()
{
net[0]=-1;
int k=-1,j=0;
while(j<lp)
{
if(k==-1||p[k]==p[j])
net[++j]=++k;
else
k=net[k];
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",p);
lp=strlen(p);
getnext();
int len=lp-net[lp];
if(net[lp]&&lp%len==0)
printf("0\n");
else
printf("%d\n",len-net[lp]%len);
}
return 0;
}