Manacher
Manacher算法是一个用来查找一个字符串中的最长回文子串(不是最长回文序列)的线性算法。它的优点就是把时间复杂度为O(\({n}^{2}\))的暴力算法优化到了O(n)。首先先让我们来看看最原始的暴力扩展,分析其存在的弊端,以此来更好的理解Manacher算法。
暴力匹配
暴力匹配算法的原理很简单,就是从原字符串的首部开始,依次向尾部进行遍历,每访问一个字符,就以此字符为中心向两边扩展,记录该点的最长回文长度。那么我们可以想想,这样做存在什么弊端,是不是可以求出真正的最长回文子串?
答案是显然不行的,我们从两个角度来分析这个算法
1.不适用于偶数回文串
我们举两个字符串做例子,它们分别是 "aba","abba",我们通过肉眼可以观察出,它们对应的最长回文子串长度分别是3和4,然而我们要是用暴力匹配的方法去对这两个字符串进行操作就会发现,"aba" 对应的最长回文长是 "131","abba" 对应的最长回文长度是 "1111",我们对奇数回文串求出了正确答案,但是在偶数回文串上并没有得到我们想要的结果,通过多次测试我们发现,这种暴力匹配的方法不适用于偶数回文串
2.时间复杂度O(\({n}^{2}\))
这里的时间复杂度是一个平均时间复杂度,并不代表每一个字符串都是这个复杂度,但因为每到一个新位置就需要向两边扩展比对,所以平均下来时间复杂度达到了O(n*n)。
Manacher算法本质上也是基于暴力匹配的方法,只不过做了一点简单的预处理,且在扩展时提供了加速
Manacher对字符串的预处理
我们知道暴力匹配是无法解决偶数回文串的,可Manacher算法也是一种基于暴力匹配的算法,那它是怎么来实现暴力匹配且又不出错的呢?它用来应对偶数字符串的方法就是——做出预处理,这个预处理可以巧妙的让所有字符串都变为奇数回文串,不论它原本是什么。操作实现也很简单,就是将原字符串的首部和尾部以及每两个字符之间插入一个特殊字符,这个字符是什么不重要,不会影响最终的结果(具体原因会在后面说),这一步预处理操作后的效果就是原字符串的长度从n改变成了2*n+1,也就得到了我们需要的可以去做暴力扩展的字符串,并且从预处理后的字符串得到的最长回文字符串的长度除以2就是原字符串的最长回文子串长度,也就是我们想要得到的结果。
这里解释一下为什么预处理后不会影响对字符串的扩展匹配
比如我们的原字符串是 "aa",假设预处理后的字符串是 "#a#a#",我们在任意一个点,比如字符 '#',向两端匹配只会出现 'a' 匹配 'a','#' 匹配 '#' 的情况,不会出现原字符串字符与特殊字符匹配的情况,这样就能保证我们不会改变原字符串的匹配规则。通过这个例子,你也可以发现实际得到的结果与上述符合。
Manacher算法核心
Man