【字符串】【KMP模板--最小循环节总结】

今天下午刚好看了一道最小循环节的题,感觉还是挺有意思的,不过自己还是看了一个下午才理解点,感觉自己好菜哎~~~

kmp算法里的next数组还有一个性质就是j-next[j]是s2的最小循环节
稍微修改下next数组的定义,这里是修改前的定义链接,我们不再要求s2[j]和s2[k]不同,我们仅需要去掉if语句,直接令s2[j] = k;修改后代码如下

void getNext()
{
    int k,j;
    k = -1;
    j = 0;
    next[j] = -1;
    while(s2[j] != '\0')
    {
        while(k != -1 &&s2[j] != s2[k])
            k = s2[k];
        next[++j] = ++k;//修改部分 
    }
    return ;
 } 

需要注意几点:
1:j-next[j]是最小循环节的长度
2:字符串的循环条件是j%(j-next[j])==0&&next[j]!=0
3:最小循环节的循环次数是j/(j-next[j])

具体的程序运行过程如下面这张图,代码在末尾我输入的字符串ababa进行测试,如果看了图还不太清楚的小伙伴可以把代码拷下去自己运行一遍,大概就了解了,实在不清楚的话,可以手动推一遍(kmp手动模拟三遍的路过)

《【字符串】【KMP模板--最小循环节总结】》

#include<stdio.h>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
char s1[1000];
int next[1000];
int l;
void getNext(char s1[],int next[])
{
    int i,j;
    j = -1;
    i = 0;
    next[i] = -1;
    while(s1[i]!='\0')
    {
        while(j!=-1&&s1[j]!=s1[i])
            j = next[j];
        i++;
        j++;
        next[i] = j;
    }
    return;
}
int main()
{
    int t,i,ans;

    while(scanf("%s",s1)!=EOF)
    {
        getNext(s1,next);
        l = ans = strlen(s1);
        i = next[l];
        while(i != -1)
        {
            int k = l - i;//最小循环节 
            int p = l%k;//循环k节点若干次后剩余部分的长度
            int q = (k-p)%k;//q为字符串s1要想补齐成恰好整数个k所需要的最少字符数 
            if( l+q >= k*2)//判断循环是否超过两次
                ans = min(ans,p);
            i = next[i];
        }
        printf("%d\n",ans);//输出最小补全长度 
    }
    return 0;
}
    原文作者:KMP算法
    原文地址: https://blog.csdn.net/hello_sheep/article/details/76924976
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞