扩展KMP学习笔记

前置芝士: KMP, manachar

告示:本文字符串下标均从 1 开始。

扩展KMP算法提供了一个计算 Z 函数的方法。

求解 Z 函数
定义 Z 函数 zi 表示字符串 s 以下标 i 为开头的后缀与 s 的最长公共前缀。

根据定义, z1=nns 的长度。


如果直接暴力求解,显然每计算一次 zi 都要花费 n 的时间,总时间是 O(n2)

不过可以通过扩展KMP算法,将此优化到 O(n)

假设我们计算 zi 时, 1j<izj 已经全部算出。

我们可以维护一个 r 最大的能与 s 前缀匹配的s[l:r]。(这句话好好理解)

对于 ir 直接将 zi 初始成 min(zil+1,ri+1), 否则为 0

然后暴力往后匹配,求出 zi, 更新之前的 l,r

因为匹配次数跟 r 相同, 所以是 O(n) 的。

CODE

复制代码
inline void getZ(char *s, int n) {
    for (int i = 1; i <= n; ++ i) z[i] = 0;
    z[1] = n;
    for (int i = 2, l = 0, r = 0; i <= n; ++ i) {
        if (i <= r) z[i] = min(z[i-l+1], r-i+1);
        while (i + z[i] <= n && s[i+z[i]] == s[z[i]+1]) ++ z[i];
        if (i + z[i] - 1 > r) l = i, r = i + z[i] - 1;
    }
}
View Code
复制代码

求解文本串的后缀与模式串的匹配

根据上文, 我们可以先求出模式串的 z 函数。

接着类似于 KMP, 我们对文本串开始对模式串进行匹配,发现计算方式与 z 函数类似,于是只要改一下就行了。

CODE

复制代码
inline void exkmp(char *s, int n, char *t, int m) {
    getZ(t, m);
    for (int i = 1; i <= n; ++ i) p[i] = 0;
    for (int i = 1, l = 0, r = 0; i <= n; ++ i) {
        if (i <= r) p[i] = min(z[i-l+1], r-i+1);
        while (i + p[i] <= n && s[i+p[i]] == t[p[i]+1]) ++ p[i];
        if (i + p[i] - 1 > r) l = i, r = i + p[i] - 1;
    }
}
View Code
复制代码

 

posted @   LikC1606  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示