似乎没什么用的字符串算法。
用于在线性时间内匹配回文子串。
回文串
字符串的回文串分为两种:奇子回文串和偶子回文串,类似于中位数的解法,奇子回文串的回文中心是一个字符,而偶子回文串的回文中心是两个字符。例如:
$abcdcba$ 是一个奇回文串,其回文中心是 $d$ ;
$abcddcba$ 是一个偶回文串,其回文中心是 $dd$ 。
回文匹配
有一个很显然的性质,回文中心的两端应该是相等的,那么,就有一种 $\mathcal O(n^2)$ 的暴力匹配思路:
枚举回文中心,向两端暴力匹配。
但有一个问题,那就是,我们无法枚举偶回文串的回文中心,所以考虑转换字符串:
$abccba\Rightarrow |a|b|c|c|b|a|$
即插入隔板,使其回文中心变成一个隔板。但这样的话,我们还需要类似于平衡树内的卫兵,即在左右分别插入一个奇奇怪怪的字符:
$!|a|b|c|c|b|a|?$
以保证在匹配的时候,不会把空字符算进匹配中。
Manacher
这个算法是在暴力的基础上进行了一个优化。因为有字符串算法线性公理(因为 $\text{Kmp,ExKmp,SAM}$ 等字符串相关的算法都是线性复杂度),所以不难猜出,$\text{Manacher}$ 算法(俗称马拉车算法)也是线性复杂度。
我们设当前的已找到的回文串的最右端点为 $mr$ ,$mr$ 所属的回文串的回文中心为 $mid$ ,注意,这里的字符串已经经过了扩倍处理。
设函数 $p(i)$ 表示以 $i$ 为回文中心的回文串的最长半径(即回文中心到其中一个端点的距离,计算公式为 $r-mid$ 或 $mid-l$),我们假定当前 $p(1)\sim p(i-1)$ 已经计算好了。
那么当前枚举的 $i$ 一定满足 $mid\leq i\leq mr$ ,那么,则一定有 $str[i]=str[2mid-i]$ ,这是回文的定义,不必多述。也正因为这样,所以会有 $p[i]=p[2mid-i]$ ,但我们无法保证是否满足 $p[i]\geq p[2mid-i]$ ,所以还需要对 $i$ 进行暴力拓展。然后更新答案。
当然,我们也要更新 $mid$ 和 $mr$ ,因为我们不需要保证当前 $mid$ 所在的回文串是最长的,只需要 $mr$ 尽可能大已让暴力拓展的次数尽量少。所以,只要当前拓展的回文大于了 $mr$ ,就直接更新就好了。
代码就三行,时间复杂度 $\mathcal O(n)$ ,虽然我不会证,但反正 $1.1\times 10^7$ 能过即可。
AC Code
1 |
|
这个算法用处不大,回文匹配也可以用字符串哈希水到 $\mathcal O(n\log n )$ ,没必要卡这个。