今天下午刚好看了一道最小循环节的题,感觉还是挺有意思的,不过自己还是看了一个下午才理解点,感觉自己好菜哎~~~
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] != ' ')
{
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]!=' ')
{
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
",ans);//输出最小补全长度
}
return 0;
}