最小循环子串

定理:假设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]。

例题:
hdu 1358 Period

题目

题意:求字符串的前缀是否为周期串,若是,打印循环节的长度及循环次数;

思路:直接从i=2遍历到n,看是否符合

代码:

#include
using namespace std;
const int N=1e6+10;
char c[N];
int Next[N];
void init(int n)
{
    int i=0,j=-1;
    while(iif(j==-1||c[i]==c[j])
        {
            i++;
            j++;
            Next[i]=j;
        }
        else
        {
            j=Next[j];
        }
    }
}
int main()
{
    int n;
    int k=1;
    while(~scanf("%d",&n)&&n)
    {
        scanf("%s",c);
        memset(Next,0,sizeof(Next));
        Next[0]=-1;
        init(n);
        printf("Test case #%d\n",k++);
        for(int i=2;i<=n;i++)
        {
            if(i%(i-Next[i])==0&&i/(i-Next[i])>1)
            {
                printf("%d %d\n",i,i/(i-Next[i]));
            }
        }
        printf("\n");
    }
    return 0;
}

poj 2406 Power Strings

题目

题意:求周期子串

思路:如果len%(len-Next[len])==0,说明是周期子串,直接相除,否则输出1.

代码:

#include
#include
using namespace std;
const int N=1e6+10;
char c[N];
int Next[N];
void init(int n)
{
    int i=0,j=-1;
    while(iif(j==-1||c[i]==c[j])
        {
            i++;
            j++;
            Next[i]=j;
        }
        else
        {
            j=Next[j];
        }

    }
}
int main()
{
    while(~scanf("%s",c))
    {
        if(c[0]=='.')break;
        memset(Next,0,sizeof(Next));
        Next[0]=-1;
        int len=strlen(c);
        init(len);
        if(len%(len-Next[len])==0)
        printf("%d\n",len/(len-Next[len]));
        else printf("1\n");
    }
    return 0;
}

你可能感兴趣的:(KMP)