题目链接(Virtual Judge)
扩展KMP(又称Z函数)的模板题,参考资料:Z 函数(扩展 KMP) - OI Wiki
Z函数定义:
一个长度为n 的字符串s。该字符串的 Z 函数 为一个长度为n 的数组,其中第 i 个元素为满足从位置 i开始且为 s前缀的字符串的最大长度。定义有点儿绕,但是也很明确。
作为对比,附上KMP算法的前缀函数的定义:next[i]为既是子串s[0~i]的前缀同时也是该子串的后缀的最长真前缀(proper prefix)长度。一个字符串的真前缀是其前缀但不等于该字符串自身。
CODE
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn=1000001;
char s[maxn];
int z[maxn];
//设从i位置开始的s的后缀串为s0i
void z_function(int n)//扩展KMP(Z函数),求s与s0i的最长公共前缀的长度
{
for(int i=0 ;i<n ;i++)
z[i]=0;
for(int i=1,l=0,r=0; i<n ; i++)
{
if(i<=r)
z[i]=min(r-i+1,z[i-l]);
while(i+z[i]<n&&s[z[i]]==s[i+z[i]])
++z[i];
if(i+z[i]-1>r)
{
l=i;
r=i+z[i]-1;
}
}
}
int main()
{
int len;
while(scanf("%s",s)!=EOF)
{
len=strlen(s);
z_function(len);
for(int i=len-1 ;i>=0 ;i--)
{
if(z[i]+i==len) //当Z函数与字符串的长度相差i时,就满足了题目要求:既是前缀又是后缀
{
printf("%d ",z[i]);
}
}
printf("%d\n",len);
}
return 0;
}