给定长 n 的字符串 S,对于每个 1≤i≤n,求出 zi 表示 lcp(S,S[i,n])。
时间复杂度 O(n)。
类似 manacher,若存在 j 满足 j<i 且 j+zj−1≥i,则 zi 至少为 min(zi−j+1,j+zj−i):
 
那么记录 p+zp−1 最大的 p,每次暴力拓展 zi 都会令 p+zp−1 增加 1,所以时间复杂度均摊 O(n)。
注意 z1 要单独计算。
代码如下:
z[1]=n;
for(int i=2,rb=2;i<=n;i++)
{
    if(rb+z[rb]-1>=i) z[i]=min(z[i-rb+1],rb+z[rb]-i);
    while(z[i]<n-i+1&&a[z[i]+1]==a[i+z[i]]) z[i]++;
    if(i+z[i]>rb+z[rb]) rb=i;
}
拓展
给定两个字符串 S,T,长度分别为 n,m。对于每个 1≤i≤n,求出 pi=lcp(S[i,n],T)。
时间复杂度 O(n+m)。
基本是一样的,先求出 T 的 z 数组,若存在 j 满足 j<i 且 j+pj−1≥i,则 pi 至少为 min(zi−j+1,j+pj−i)。那么记录 r+pr−1 最大的 r 即可,时间复杂度还是线性的。
例题:P5410 【模板】扩展 KMP/exKMP(Z 函数)