学习 Z 函数
前言
- 回旋镖终于是飞回来了。。。
- 该学的都得学
\(Z\>\>function\)
- \(Z\) 函数算法又叫 \(exKMP\),目的是在 \(O(n)\) 的线性复杂度内求出一个字符串对于每一个后缀的 \(LCP\) 长,将 \(Z\) 函数定义为一个字符串对于每一个后缀的 \(LCP\) 长,并定义 \(Z_0 = 0\)
\(LCP\):最长公共前缀
- 例子:\(s=aaaaa,Z=[0,4,3,2,1]\)
- 这个用枚举比较法可以 \(O(n^2)\) 求,但是我们要 \(O(n)\)
- 给出 \(O(n)\) 计算的方法
- 为了方便下标从 \(0\) 开始
- 维护 \([l,r]\) 表示右端点最靠右的匹配段,使其初始均为 \(0\)
- 如果 \(i\) 是 \(\le r\) 的,我们发现 \(s[i,r] = s[i-l,r-l]\),所以我们可以用之前的 \(z\) 函数的值求解,有 \(z_i \ge \min(z_{i-l},r-i+1)\),所以:
- 当 \(z_{i-l} < r-i+1\),直接转移 \(z\) 函数,即 \(z_i = z_{i-l}\)
- 否则使 \(z_i = r-i+1\) 并暴力扩展
- 如果 \(i>r\),还是暴力做,求出 \(z[i]\)
- 当 \(i+z_i-1>r\) 时,我们需要更新 \([l,r]\),使:\(l=i,r=i+z_i-1\)
- 行了,就是写代码了
点击查看代码
int z[maxn];
void Z(string s)
{
int len=s.size();
int l=0,r=0;
for (int i=1;i<len;i++)
{
if (i<=r && z[i-l]<r-i+1)
z[i]=z[i-l];
else
{
z[i]=max(0,r-i+1);
while (i+z[i]<len && s[z[i]] == s[i+z[i]]) z[i]++;
}
if (i+z[i]-1>r)
l=i,r=i+z[i]-1;
}
}
$\mathscr{msjing}$

浙公网安备 33010602011771号