ranslated to ENGLISH VERSION
源于这两篇文章:
http://blog.csdn.net/ggggiqnypgjg/article/details/6645824
http://zhuhongcheng.wordpress.com/2009/08/02/a-simple-linear-time-algorithm-for-finding-longest-palindrome-sub-string/
这个算法看了三天,终于理解了,在这里记录一下本身的思路,省得之后忘了又要想好久- -.
首先用一个很是巧妙的方式,将全部可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每一个字符的两边都插入一个特殊的符号。好比 abba 变成 #a#b#b#a#, aba变成 #a#b#a#。 为了进一步减小编码的复杂度,能够在字符串的开始加入另外一个特殊字符,这样就不用特殊处理越界问题,好比$#a#b#a#(注意,下面的代码是用C语言写就,因为C语言规范还要求字符串末尾有一个'\0'因此正好OK,但其余语言可能会致使越界)。
下面以字符串12212321为例,通过上一步,变成了 S[] = "$#1#2#2#1#2#3#2#1#";
而后用一个数组 P[i] 来记录以字符S[i]为中心的最长回文子串向左/右扩张的长度(包括S[i]),好比S和P的对应关系:php
那么怎么计算P[i]呢?该算法增长两个辅助变量(其实一个就够了,两个更清晰)id和mx,其中id表示最大回文子串中心的位置,mx则为id+P[id],也就是最大回文子串的边界。
而后能够获得一个很是神奇的结论,这个算法的关键点就在这里了:若是mx > i,那么P[i] >= MIN(P[2 * id - i], mx - i)。就是这个串卡了我很是久。实际上若是把它写得复杂一点,理解起来会简单不少:web
固然光看代码仍是不够清晰,仍是借助图来理解比较容易。
当 mx - i > P[j] 的时候,以S[j]为中心的回文子串包含在以S[id]为中心的回文子串中,因为 i 和 j 对称,以S[i]为中心的回文子串必然包含在以S[id]为中心的回文子串中,因此必有 P[i] = P[j],见下图。
当 P[j] >= mx - i 的时候,以S[j]为中心的回文子串不必定彻底包含于以S[id]为中心的回文子串中,可是基于对称性可知,下图中两个绿框所包围的部分是相同的,也就是说以S[i]为中心的回文子串,其向右至少会扩张到mx的位置,也就是说 P[i] >= mx - i。至于mx以后的部分是否对称,就只能老老实实去匹配了。
对于 mx <= i 的状况,没法对 P[i]作更多的假设,只能P[i] = 1,而后再去匹配了。
因而代码以下:算法
OVER.
#UPDATE@2013-08-21 14:27
@zhengyuee 同窗指出,因为 P[id] = mx,因此 S[id-mx] != S[id+mx],那么当 P[j] > mx - i 的时候,能够确定 P[i] = mx - i ,不须要再继续匹配了。不过在具体实现的时候即便不考虑这一点,也只是多一次匹配(必然会fail),可是却要多加一个分支,因此上面的代码就不改了。
数组
--wordpress