KMP,AC 自动机,以及 fail 树
作者:互联网
开坑待填。
六个月后,yukari1735 准备开始填坑。
全文大概无图!
\(\bold{Border}\)
对于一个字符串 \(s\),若 \(s\) 的一个前缀 \(p\) 同时也是 \(s\) 的后缀且 \(p\neq s\),那么称 \(p\) 为 \(s\) 的一个 \(\text{border}\)。
\(\emptyset\) 也是 \(s\) 的 \(\text{border}\)。\(|\emptyset|=0\)。
记字符串 \(s\) 的 \(\text{border}\) 集合为 \(B(s)\)。
\(\bold{Next}\)
对于一个字符串 \(s\),\(\mathrm{next}_i\) 定义为 \(s\) 的 \(i\) 前缀 \(s_{1,i}\) 中的最长 \(\text{border}\) 长度(或结尾下标)。形式化一点就是 \(\mathrm{next}_i=\max\{|x|:x\in B(s_{1,i})\}\)。
通过不断地跳 \(\mathrm{next}\) 指针,我们可以遍历 \(s\) 的所有 \(\text{border}\)。因为对于 \(s\) 的两个 \(\text{border}\) \(x,y\ (|x|<|y|)\),\(x\) 也是 \(y\) 的 \(\text{border}\)。
所以我们可以得到一个求 \(\mathrm{next}\) 的方法:设当前已经求出了 \(s_{1,i}\) 的 \(\mathrm{next}\),我们直接用上面的方法遍历 \(s_{1,i}\) 的所有 \(\text{border}\),检查是否有 \(\text{border}\) 可以匹配 \(s_{i+1}\)。
实际上该算法时间复杂度 \(O(|s|)\)。证明,我也不会 qwq!
\(\bold{Period}\)
称 \(p\) 为字符串 \(s\) 的一个周期,仅当 \(s_i=s_{i+p}\) 对于所有 \(1\leq i\leq |s|-p\) 都成立。
考虑 \(s\) 的一个 \(\text{border}\) \(x\),其对应着一个长度为 \(|s|-|x|\) 的周期。
同样地,一个周期 \(p\) 也对应着 \(s\) 的一个 \(\text{border}\) \(x=s_{1,|s|-p}\)。
也即所有的周期与 \(s\) 的 \(\text{border}\) 存在一一对应的关系,所以我们只需求出 \(B(s)\)。
\(\bold{KMP}\)
在主串 \(t\) 中对单个模式串 \(s\) 进行匹配。时间复杂度 \(O(|t|+|s|)\)。
首先求出 \(s\) 的 \(\mathrm{next}\),接着从 \(t\) 的起始位置开始匹配,设当前匹配到 \(t_i\) 和 \(s_j\),且当前匹配是合法的,那么下一步尝试匹配 \(t_{i+1}\) 和 \(s_{j+1}\),若成功则 \(i\rightarrow i+1,j\rightarrow j+1\),继续循环。
否则我们遍历 \(s_{1,j}\) 的所有前缀 \(s_{1,k}\),若其也为 \(t_{i-j+1,i}\) 的后缀,则尝试匹配 \(s_{k+1}\) 和 \(t_{i+1}\),由于当前有 \(s_{1,j}=t_{i-j+1,i}\),所以这些前缀 \(s_{1,k}\) 都为 \(s_{1,j}\) 的 \(\text{border}\),用跳 \(\mathrm{next}\) 的方法遍历即可。匹配到后令 \(i\rightarrow i+1,j\rightarrow k+1\),继续循环。
当 \(j=|s|\) 时,匹配成功。
关于它的时间复杂度为什么线性,我也不会证 qwq!
标签:AC,匹配,bold,text,next,KMP,fail,border,mathrm 来源: https://www.cnblogs.com/yukari1735/p/15855833.html