有一段時間沒有更新博客了, 今天看到這個算法,挺神奇的,哈哈哈,特意轉載一波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)