kmp求最小循環節

轉自: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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章