【学习笔记】KMP 相关算法

Page Views Count

KMP#

单模式串匹配,比较平凡所以不说了,比较有借鉴意义的每次拓展一位和 nxt 数组能极大减少不合法的匹配,时间复杂度 O(|s|+|t|)

引出一个定义,记满足 s[1,i]=s[|s|i+1,|s|] 的前缀为字符串 sborder,所有的 border 构成 Border(s) 集合。

失配树#

KMP 处理 nxt 数组时是一个类似 nxtij 的操作,可以看作连边,根节点是 0,一个前缀对应节点的全部祖先恰好是这个前缀的 Border 集合。那么求两个前缀的最长公共 border 就是树上 LCA,可能需要分是否是祖先关系讨论一下。

KMP 自动机#

就是只有一个模式串版本的 AC 自动机,只要从 nxti 构建转移指针就行,目测用处不大。

Z 函数#

又叫扩展 KMP。

算法思想#

定义 Z 函数 zi=lcp(s,s[i,|s|]),即后缀和原串的 lcp

考虑维护当前最右端的区间 [l,r],扩展的方法类似 Manacher:

  • i>r,直接暴力拓展;

  • ir,那么 s[1,rl+1]=s[l,r],于是 s[il+1,rl+1]=s[i,r],那么 zimin(zil+1,ri+1),设为初始值再暴力拓展即可。

复杂度是线性的,证明考虑暴力拓展非 O(1) 次时 r 必然增大。

例题#

CodeForces-432D Prefixes and suffixes *2000#

zi=|s|i+1 的就是 border,查询出现次数就是 zil 的位置个数。

Periodicity Lemma#

定义 ps 的一个周期当且仅当对于 1i|s|p,有 si=si+p。感性理解就是周期就是一个字符串划分成若干相等的段,最后一段可以是这些段的一个前缀。

Weak Periodicity Lemma:若 p,q 都是字符串 s 的周期且 p+q|s|,则 gcd(p,q) 也是 s 的周期。

直观来看 p,q 导出 gcd(p,q) 是类似辗转相除的跳来跳去,存在一个问题:如果将字符串按照两个周期分别补充成无限长,得到的结果可能不相等,例如 abaababa 如果按 abaababaabab 补充肯定是不相等的,那么跳来跳去就可能出错,所以有一个长度的限制。

弱周期引理的证明比较简单,考虑归纳,规定 pq,假设已经证明对于任意 x<p,y<q 都是成立的,而 p=1 时显然也成立。由于 p+q|s|pq,可以将 1i|s| 划分成 i|s|qi>|s|q 两部分。对于前者,i+qi+qp 都在 [1,|s|] 范围内,于是 si=si+qp;对于后者,实际考虑 p|s|q<i|s|(qp)ipip+q 都在范围内,于是 si=sip+qqp 就是 s 的一个周期,而根据归纳 gcd(qp,p)=gcd(p,q) 也是 s 的一个周期。


Periodicity Lemma:若 p,q 都是字符串 s 的周期且 p+qgcd(p,q)|s|,则 gcd(p,q) 也是 s 的周期。

有一个生成函数证明,感觉很有趣。记 P(x),Q(x) 分别为长度为 p,q 的周期,Sp(x),Sq(x) 分别为按照周期补充的无限长串,那么满足:

Sp(x)=P(x)1xpS(x)(modx|s|)

Sq(x)=Q(x)1xqS(x)(modx|s|)

于是可以得到:

Sp(x)Sq(x)=P(x)1xpQ(x)1xq=1xgcd(p,q)(1xp)(1xq)(P(x)(1xq)1xgcd(p,q)Q(x)(1xp)1xgcd(p,q))

把后面的东西记作 F(x),观察可知 degF(x)<p+qgcd(p,q)|s|,而 Sp(x)Sq(x)0(modx|s|),所以 F(x)0(modx|s|),根据其度数知 F(x)=0,所以 Sp(x)=Sq(x),不需要截取,所以后面就能按照辗转相除证明了。

Border Series#

内容#

主要是证明一个性质:一个字符串 sBorder 可以划分为 O(logn) 个等差数列。

首先考虑任意一个 border s[1,i],发现 s 有长为 |s|i 的周期,这个画一画图就容易得到。

那么取出所有长度 |s|2border,其中最长的一个就对应了 s 的最小周期 p,发现取任意 p 的倍数也能得到一个周期,现在需要证明这些周期中不含不是 p 的倍数且夹在两个倍数之间的。考虑另一个周期 q,若 p+q|s|,即满足 Weak Periodicity Lemma,那么一定有 pq,否则 gcd(p,q)<p,那么 p 就不是最小周期了。这里取出的长度为 |s|2border 对应的周期一定 |s|2,因此二者之和一定满足 Weak Periodicity Lemma 的限制。

于是证明了所有长度 |s|2border 构成了一个公差为最小周期的等差数列,考虑找到剩下的 border 中最长的一个,将其作为整个串,继续这样处理,只需要 O(logn) 次就结束了。

之后不妨再来看看放在失配树是什么样子:就是把根到 n 节点链划分成 O(logn) 条等差数列,同时如果失配树上有分叉,那么一定是某个等差数列的首项。

例题#

Luogu-P5829 失配树#

考虑不用失配树做。

考虑当前节点 x,记 d=xnxtx,若 2dx,则再往下减少 border 的长度就不符合长度大于二倍的要求了,所以 x 就是链顶;否则取 xmodd+d 就是链顶,每次选链顶编号大的跳上去。

Luogu-P4156 WC 2016 论战捆竹竿#

相当于每次加上除去 border 的部分,是同余最短路问题。

降低复杂度需要从 Border Series 入手,得到 O(logn) 个三元组 (a,d,l),表示可以增加长度为 a+id 的字符串,其中 i[0,l]

对每种等差数列依次考虑肯定是正确的,对三元组 (a,d,l) 求模 a 的同余最短路,转移会形成 gcd(a,d) 个环,可以对这些环分别考虑。其中转移前的最小值一定不会被转移,也不会有其他转移跨过这个最小值,可以从这个位置断开,之后转移只剩 l 的限制,可以单调队列优化。

之后考虑如何把模 a 的同余最短路转成模 a 的同余最短路,不妨看做多源,初始值 figfimoda,同样也形成了 gcd(a,a) 个环,选最小值断开,此时转移没有任何限制,直接前缀 min 优化就行了。

参考资料#

Z 函数#

周期引理#

Border Series#

作者:SoyTony

出处:https://www.cnblogs.com/SoyTony/p/17955245/Learning_Notes_about_KMP_Related_Algorithms

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   SoyTony  阅读(126)  评论(3编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示