Manacher's ALGORITHM: O(n)時間求字符串的最長迴文子串

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

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  1
(p.s. 能夠看出,P[i]-1正好是原字符串中迴文串的總長度)


那麼怎麼計算P[i]呢?該算法增長兩個輔助變量(其實一個就夠了,兩個更清晰)id和mx,其中id表示最大回文子串中心的位置,mx則爲id+P[id],也就是最大回文子串的邊界。

而後能夠獲得一個很是神奇的結論,這個算法的關鍵點就在這裏了:若是mx > i,那麼P[i] >= MIN(P[2 * id - i], mx - i)。就是這個串卡了我很是久。實際上若是把它寫得複雜一點,理解起來會簡單不少:web

//記j = 2 * id - i,也就是說 j 是 i 關於 id 的對稱點。
if  (mx - i > P[j])  
    P[i] = P[j];
else  /* P[j] >= mx - i */
    P[i] = mx - i; // P[i] >= mx - i,取最小值,以後再匹配更新。


固然光看代碼仍是不夠清晰,仍是藉助圖來理解比較容易。

當 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,而後再去匹配了。

因而代碼以下:算法

//輸入,並處理獲得字符串s
int  p[1000], mx = 0, id = 0;
memset(p, 0,   sizeof(p));
for  (i = 1; s[i] != '\0'; i++) {
    p[i] = mx > i ? min(p[2*id-i], mx-i) : 1;
      while  (s[i + p[i]] == s[i - p[i]]) p[i]++;
      if  (i + p[i] > mx) {
        mx = i + p[i];
        id = i;
    }
}
//找出p[i]中最大的


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

相關文章
相關標籤/搜索