扩展kmp

· · 个人记录

扩展kmp(Z Algorithm)

引入

移除字符串的一部分,加上一部分,问多少步能变回原样(移除几个加上几个)

定义

是一种字符串算法。

核心:z数组

可以在O(n + m)的时间复杂度内,在给定的文本串T和一个模式串P中,找到所有匹配的位置。

Z函数

核心是z(i)

定义为:字符串s与s[i, ....... , n - 1]的最长公共前缀(LCP)

Z(i)是满足s[0, ....., x - 1]与s[i, ....., i + x - 1]

令Z(0) = 0

例子:

Z-box

这个过程就像啃老,老人死了就啃不了。
---------林老师

构建Z数组

通过维护一个窗口 Z-box ,利用已知信息高效计算Z函数

对于每个位置 $i

快速求Z函数

情况1 i > r

当你做不了富二代,啃不了老,你就努力做个富一代,让别人啃你。 -------林老师

代码

if(i > r){
    while(i + z[i] < n && s[z[i]] == s[i + z[i]])
        z[i]++;
    l = i;
    r = i + z[i] - 1;
}

情况2 i \le r z[i - l] < r - i + 1

else if(z[i - l] < r - i + 1)
    z[i] = z[i - l];

情况3 i \le r z [i - l] \ge r - i + 1

else{
        z[i] = r - i + 1;
        while(i + z[n] < n && s[z[i] == s[i + z[i]]])
            z[i] ++;
        l = i;
        r = i + z[i] - 1;
    }

其实

情况1和3可以合并

for(int i = 1, l = 0, r = 0; i < n; i ++){
    if(z[i - l] < r - i + 1)
        z[i] = z[i - l];
    else{
        z[i] = max(r - i + 1, 0);
        while(i + z[i] < n && s[z[i] == s[i + z[i]]])
            z[i] ++;
        l = i;
        r = i + z[i] - 1;
    }
}

复杂度是O(n),因为内层循环每执行一次,都会使r加1,执行次数不会超过n次。