問題提出
問:給定乙個字串,要求其最長回文子串。
例如:
「aaaa」,其最長回文子串為4,即「aaaa」,
「abcd」,最長回文子串為1,
「abccb」,最長回文子串為4,即「bccb」。
如果直接對每乙個字元遍歷,分別向兩邊查詢的話,時間複雜度為o(n
2n^2
n2),效率很低。
那有沒有更高效的演算法呢。
2023年,乙個叫manacher的人發明了一種演算法,即manacher演算法,時間複雜度可以達到o(n
nn)。
演算法描述
1 、1、
1、預處理
由於回文串分為奇回文(長度為奇數)、和偶回文(長度為偶數),本因分兩種情況處理,但為了簡化這一步,我們將對原字串進行處理,使之變成奇回文。
具體做法是在每個字元左右兩邊都加上乙個特殊字元,如:
原字串為,abba,長度為4,
處理後,#a#b#b#a#,長度為9。
原字串為,aba,長度為3,
處理後,#a#b#a#,長度為7。
2 、2、
2、最長回文子串長度
我們引入乙個輔助陣列,int p[ ]
,p[i]
表示以原字串s
中i
位置處s[i]
為中心的最長回文半徑。
以字串abbaf
為例,預處理後字串為#a#b#b#a#f#
i 012
3456
78910
1112
arr[i] # c # a # b # b # a # f #
p[i]12
1212
5212121
在上面這個例子中,最長回文子串為abba
。以s[6]
為中心,其最長回文半徑為p[6]=5
,所覆蓋的字串是#a#b#b#a#
,對應的原始字串為abba
,即最長回文子串,長度為4
,可以通過5-1
得到。
接下來我們來**最長回文子串長度和最長回文半徑之間的關係。
再看幾個例子,aba
, 轉換之後為#a#b#a#
,最長回文子串為aba
,長度為3
,最長回文半徑為p[4]=4
。
再如,#a#e#f#e#a#
,最長回文子串為aefea
,長度為5,計算得最長回文半徑為p[6]=6
。
我們發現,最長回文子串長度=最長回文半徑-1
,即p[i]-1
。
事實上,的確存在這個結論。我們可以這樣理解,最長回文子串即以某一點i
為中心,以p[i]
為半徑所覆蓋的線段,那麼對於原始字串最長回文子串長度=p[i]*2
。由於預處理後,每個字元左右都加了乙個特殊字元,所以最長回文半徑變為了原來的2
倍,最長回文子串長度變為了原來的*2-1
,那麼最長回文子串長度=p[i]-1
。
3 、3、
3、計算p陣列
現在知道了要求的最長回文子串長度與最大回文半徑p[i]
有關,那麼接下來就討論最大回文半徑p[i]怎麼求。
我們設定兩個變數id
、mx
,id
表示能延伸到最右端的回文子串的中心位置,mx
表示該子串的最右端位置。
那麼有,mx=id+p[id]
。
對於i4
、4、
4、參考** c++
char s[maxn]
;//原始字串
char s1[maxn]
;//預處理後字串
char p[maxn]
;//最長回文半徑
intinit()
//預處理
s1[j]
='\0'
;//處理邊界,防止越界
return j;
//返回處理後的字串長度
}int
manacher()
//計算最長回文子串長度
maxlen=
max(maxlen,p[i]-1
);}return maxlen;
//返回最長回文子串長度
}
5、5、
5、參考習題
洛谷p3805 【模板】manacher演算法
orhdu3068 最長回文
Manacher 馬拉車演算法
給定乙個字串,求出其的最長回文子串 乙個將時間複雜度優化到o n 的演算法 暴力演算法,但不是純暴力,即按照做過的事情不再去做來優化 我們知道,乙個回文串要麼是奇數的串 aba 要麼是偶數的串 abba 可以看出,乙個回文串有乙個對稱軸 對於奇數串aba來說,對稱軸就是b 而對於偶數串abba來說,...
Manacher演算法(馬拉車)
演算法總結第三彈 manacher演算法,前面講了兩個字串相演算法 kmp和拓展kmp,這次來還是來總結乙個字串演算法,manacher演算法,我習慣叫他 馬拉車 演算法。相對於前面介紹的兩個演算法,manacher演算法的應用範圍要狹窄得多,但是它的思想和拓展kmp演算法有很多共通支出,所以在這裡...
馬拉車演算法manacher
1.預處理解決奇回文和偶回文問題 比如 str bcbaa 在每個字元的開頭,結尾和中間插入乙個特殊字元 來得到乙個新的字串 b c b a a 這樣對於原來字串中的奇回文 bcb 來說,在新的字串中變成了 b c b 還是奇回文,只是回文串長度從3變成了7 注意 中 i 1 0,與1按位與,如果i...