z函数(扩展kmp)

两个重要的点:1.i - l

                         2.r

一个简单的证明:

        \begin{aligned} &s[(i)+(x)]\\ =&s[(l)+(i+x-l)]\\ =&s[(0)+(i+x-l)]\color{red}{(x\le l+z(l)-i)}\\ =&s[(i-l)+(x)]\\ =&s[(0)+(x)]\color{red}{(x\le z(i-l))}\\ \end{aligned}

(来源:题解-洛谷P5410 【模板】扩展 KMP(Z 函数) - George1123 - 博客园

借助前面处理的两个点来避免重复匹配

代码:

void exkmp(string x)//匹配本身
{
    l = 0;
    lz = x.length();
    for (i = 1; i < lz; i++)//最好从1开始,0预处理掉
    {
        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] < lz && x[z[i]] == x[ i + z[i] ] ) z[i]++;
        }
        if(i + z[i] - 1 > r) l = i,r = i + z[i] - 1;
    }
}

注意一个点:

        最好是把z[0]和r赋值为0,因为在最下面的if判断里,如果r的初始值为l + z[l] 或者干脆不写r,把r直接换成l + z[l] - 1,当z[l] == maxx且l == 0时,l + z[l]很大,影响更新,拖慢速度

        当然不同的题需要特殊判断,这里是同串匹配

关于第一个if:

        可以证明:x[i + z[i]] != x[z[i]],因为如果这样,z[i - l]在处理时一定会往后延伸

关于else:

        i + z[i] 不能再加1,我当时就犯了这个错

        由于l总是最大,匹配的字符总是新的,所以O(n)

好的文章:
题解-洛谷P5410 【模板】扩展 KMP(Z 函数) - George1123 - 博客园

Z函数(扩展KMP)&前缀函数的总结~ - NuoCarter - 博客园

posted @ 2022-07-13 19:57  此间无物  阅读(85)  评论(0)    收藏  举报