马拉松算法:
马拉松算法是用来计算一个字符串中最长的回文字符串(对称字符串,如aba abba)。
首先,我们拿到一个字符串S,然后在S中的每个字符之间加#。
例如:S="abcb" T="a#b#c#b"
我们T字符串的每一个T[i]向延伸d个字符 使得 T[i-d,i+d]是一个回文字符串。你会立刻发现,d就是以T[i]为中心的最长回文字符串的长度。
我们建立一个P数组,是的P数组的长度等于T的长度,每一个P[i]的值表示对应的T[i]为中心的最大回文字符串的长度。
如下:
T = # a # b # a # a # b # a # P = 0 1 0 3 0 1 6 1 0 3 0 1 0
瞅一下P,我们立刻就能发现最长的回文字符串长度是P[6],对应字符串是"abaaba"。
你有没有发现,加入#之后 以前的奇数回文字符串 和 偶数回文字符串都变得优雅了呢(提示:这仅仅是为了方便讲解,不是算法代码里所必须的步骤)。
现在,想象你在回文字符串"abaaba"的中间画一条线,你会发现P两边的数字也是关于这条线对称的。不仅仅是这个字符串,你试试"aba"也是一样的情况。
这是巧合吗?答说是也是,说不是也不是。这只是在某种条件下才会出现的,不管怎么样,我们已经取得了很大的进步。
让我们来看看更为复杂的字符串"babcbabcbaccba"。

上图展示一个从P基于T的生成过程,假设你已经完成P的一部分。竖实线标记的是回文字符串"abcbabcba"的正中间C,两个竖虚线标记回文字符串的左边界和右边界。
你在i这个位置,且i位置关于C的镜像位置是i'。你应该如何能快速计算出P[i]的值呢。
我们看到,i=13,i'=9,我们需要计算的是P[13]。

上图两个绿实线所覆盖的区域关于C对称。我们看一下i的镜像i',很显然P[i']=P[i]=1。P[i]必然是1,因为回文字符串属性关于中间对称。
对称点C之后的三个属性,都是对称的,P[ 12 ] = P[ 10 ] = 0, P[ 13 ] = P[ 9 ] = 1, P[ 14 ] = P[ 8 ] = 0。

当i=15时,P[i]应该是多少呢?如果我们根据上面的逻辑,P[i]应该与P[i']的值相同,为7。但这是错的,我们以T[15]为中心展开,会得到回文字符串a#b#c#b#a,这要比我们预测的回文字符串要短,为什么的。

很显然,绿色实现覆盖的区域是关于中心对称的,绿色虚线覆盖的局域也必然是关于中心对称的。我们发现P[i']为7且沿着它展开可以一直展开到最左边(越过了边界L到红色实线区域)。因为P[i']关于P[i]对称且延伸超过了左边界,我们可知P[i]>=5(根据上面属性对称理论P[i]至少能延伸到右边界)。在这种情况下,因为T[1]!=T[21],因此P[i]=5。
让我们总结上面关键部分的算法。
if P[ i’ ] ≤ R – i, then P[ i ] ← P[ i’ ] else P[ i ] ≥ P[ i’ ]. (Which we have to expand past the right edge (R) to find P[ i ].
好了,接下来总结第二点,就是何时C和R一起向右移动。