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

来源:互联网 发布:淘宝单笔如何部分退款 编辑:程序博客网 时间:2024/05/18 02:26

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

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手动模拟三遍的路过)

最小循环节

#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;}
原创粉丝点击