有一段时间没有更新博客了, 今天看到这个算法,挺神奇的,哈哈哈,特意转载一波html
出处: http://www.cnblogs.com/TenosDoIt/p/3675788.html算法
Manacher算法,时间复杂度O(n), 空间复杂度O(n)c#
该算法首先对字符串进行预处理,在字符串的每一个字符先后都加入一个特殊符号,好比字符串 abcd 处理成 #a#b#c#d#,为了不处理越界,在字符串首尾加上不一样的两个特殊字符(c类型的字符串尾部不用加,由于自带‘\0’),这样预处理后最终变成$#a#b#c#d#^,通过这样处理后有个好处是原来的偶数长度和奇数长度的回文在处理后的字符串中都是奇数长度。假设处理后的字符串为s 本文地址数组
对于已经预处理好的字符串咱们用数组p[i]来记录以字符S[i]为中心的最长回文子串向左/右扩张的长度(包括S[i]),以字符串“12212321”为例,p数组以下3d
s: $ # 1 # 2 # 2 # 1 # 2 # 3 # 2 # 1 # ^
p: 1 2 1 2 5 2 1 4 1 2 1 6 1 2 1 2 1htm
能够看出,P[i]-1正好是原字符串中回文串的总长度, 若是p数组已知,遍历p数组找到最大的p[i]就能够求出最长回文的长度,也能够求出回文的位置blog
下面给出求p[]数组的方法:字符串
设id是当前求得的最长回文子串中心的位置,mx为当前最长回文子串的右边界(回文子串不包括该右边界),即mx = id + p[id]。记j = 2*id – i ,即 j 是 i 关于 id 的对称点。get
1、 当i < mx 时,以下图。此时能够得出一个很是神奇的结论p[i] >= min(p[2*id - i], mx - i),下面咱们来解释这个结论博客
如何根据p[j]来求p[i]呢,又要分红两种状况
(1.1)当mx – i > p[j], 这时候以S[j]为中心的回文子串包含在以S[id]为中心的回文子串中,因为 i 和 j 对称,以S[i]为中心的回文子串必然包含在以S[id]为中心的回文子串中,因此 P[i] 至少等于 p[j], 后面的再继续匹配。以下图
注:这里其实p[i]必定等于p[j],后面不用再匹配了。由于若是p[i]后面还能够继续匹配,根据对称性,p[j]也能够继续扩展了
(1.2)当mx – i <= p[j], 以S[j]为中心的回文子串不彻底包含于以S[id]为中心的回文子串中,可是基于对称性可知,下图中两个绿框所包围的部分是相同的,也就是说以S[i]为中心的回文子串,其向右至少会扩张到mx的位置,也就是说 P[i] 至少等于 mx - i,至于mx以后的部分是否对称,就只能老老实实去匹配了。
注:若是mx – i < p[j] ,这时p[i]必定等于mx - i, 由于若是p[i]在mx以后还能够继续匹配,根据对称性,mx以后匹配的点(包括mx)必定会出如今my的前面,这说明p[id]也能够继续扩展了
2、当i >= mx, 没法对p[i]作更多的假设,只能p[i] = 1,而后再去匹配
算法复杂度分析:根据斜体字部分的注释,只有当mx-i = p[j]时 以及 i > mx时才要扩展比较,而mx也是在不断扩展的,整体而言每一个元素比较次数是n的线性关系,因此时间复杂度为O(n)