声明:下边的例子均表示下标从1开始的数组
ne数组的定义:
next[i] 就是使子串 s[1…i] 有最长相等前后缀的前缀的最后一位的下标。ne[i]也可以表示相等子串的长度
准备执行j=ne[j]时, 表示当前s[i]!=p[j+1] , 如果ne[j]=1 ,那么下一次匹配从p数组的第二个字符(也就是p[j+1])开始比较是否s[i]=p[j+ 1]
a b a b a b c a b
1 2 3 4 5 6 7 8 9
a b a b a b c a b
1 2 3 4 5 6 7 8 9
同理:ne数组的建立也是这样的,从数组的第二个字符开始枚举,因为第一个字符没有相同的字串,从i=2,j=0,开始枚举,
i=2,j=0 p[i] != p[j+1] ne[2]=0;
i=3,j=0 p[i]==p[j+1] ,j++,ne[3]=1;
i=4,j=1 p[i]==p[j+1] ,j++,ne[4]=2;
i=5,j=2 p[i]==p[j+1] ,j++,ne[5]=3;
i=6,j=3 p[i]==p[j+1] ,j++,ne[6]=4;
i=7,j=4 p[i]!=p[j+1] (此时两者不相等,那么执行j=ne[j] ,j=2,(刚才想样例时发现,为什么下一次比较不直接比较j+1=5,i=7呢?想了一下,其实这和在s数组中和p数组相等的字串问题一样,此时p数组才走到j=4,那么 j 退一下,只能退到 j = ne[i] ) 发现p[i]!=p[j+1],继续执行j=ne[j] ,j=0,所以下一次比较就从0开始比较)
(其实直接看ne数组的更新比较绕,可以对比s数组和p数组的匹配,两者其实是一样的,就上边最后一步 j -----> 0来说,下一次s数组的s[i]要和p数组的p[1]比较)
可以通过求ne数组,来确定最小循环节。
最小循环节的长度:当前枚举到的(字符串长度) i - ne[i] =t , 如果 t 满足 i%t==0 &&i/t>=2 ,那么就出现了最小循环节。
分析:观察样例发现,每次后边加的都是剔除字符串t的最长的前缀和后缀相等的子串后剩下的字符串,那么就可以用KMP求最长字串的长度(也就是 ne[n] )
#include
#include
#include
using namespace std;
const int N = 55;
int n, m;
char str[N];
int ne[N];
int main()
{
scanf("%d%d", &n, &m);
scanf("%s", str + 1);
for (int i = 2, j = 0; i <= n; i ++ )
{
while (j && str[i] != str[j + 1]) j = ne[j];
if (str[i] == str[j + 1]) j ++ ;
ne[i] = j;
}
// cout<
周期(最小循环节)
代码
#include
using namespace std;
const int N = 1e6 + 10;
char p[N];
int ne[N];
int main()
{
int t=1;
int n;
while(scanf("%d",&n),n!=0)
{
scanf("%s",p+1);
for(int i=2,j=0;i<=n;i++)
{
while(j && p[i]!=p[j+1]) j=ne[j];
if(p[i]==p[j+1]) j++;
ne[i]=j;
}
printf("Test case #%d\n",t++);
for(int i=2;i<=n;i++)
{
int t=i-ne[i];
if(i%t==0 && i/t>=2)
{
printf("%d %d\n",i,i/t);
}
}
puts("");
}
return 0;
}