最長回文子串(Manacher演算法)

2021-09-10 05:55:10 字數 1666 閱讀 8352

又是刷oj的一天。

上題

題目描述:

jiangyu有乙個長度為n的僅包含小寫字母的字串。他想找出其中最長的回文子串。。

輸入:乙個字串s,∣s∣≤1e6

輸出:乙個整數,最長回文子串長度

樣例輸入

caaaaab

樣例輸出

5

題意很簡單,求出最長的回文子串,暴力試一下? 從每個字元開始雙向擴充套件,記錄最長回文子串。對於1e6的資料量,時間複雜度為o(n*n)的演算法,可以直接pass了。那麼又有什麼好的辦法來解決最長回文子串的問題呢?答案就是——manacher馬拉車演算法。這個演算法十分巧妙。可以在o(n)的時間複雜度內求出答案。那麼他是怎麼實現的呢?我們一起來看一下

首先我們在求回文子串時候存在乙個問題,就是子串長度為奇和偶數的時候是不太一樣的。所以我們必須分開討論,為了避免分枝,我們要想乙個辦法,將奇子串和偶子串和為一種情況來討論。方法如下:

將原字串的字元之間填充符號#,就是將

aca 變為 #a#c#a#

acmmca 變為 #a#c#m#m#c#a#

這樣所有的回文串的長度都變成了奇數,就不用再分情況討論了。

可是這樣加完填充符號以後,如何知道原先回文子串的長度呢,這時我們引入回文半徑r,使用乙個r陣列,r[i]表示該字元為中心的最長回文子串的半徑。對於acmmca來說,長度為6,對於增加完填充字元以後,最中間的#字元的回文半徑為7。和原回文串的長度相差1。這是乙個普遍規律

r[i] - 1正好是原字串中最長回文串的長度
所以現在問題就轉化為,求所有r[i]中最大的,將其減1就是最長回文子串的長度。

那麼怎麼求r[i]呢?

首先引入兩個變數id和mx

id為目前為基準字串的下標值

mx就是以id為中心的最長回文子串可以延伸到的最遠距離

以id為基準,如果求i為中心的最長回文子串,如果i > mx ,則老老實實求,如果i < mx,我們可以找到i關於id的對稱的j ,如果r[j]<=mx-i,因為在mx範圍內,所以r[i]的值等於r[j],最長回文子串長度相同。

如果r[j]>mx-i,不能保證i在mx之後還是不是回文的,但是最起碼在i~mx之間還是回文的,那麼i的回文長度最起碼是mx-i所有r[i] = mx - i;

有了這個思想,演算法就不難寫出來了。

#include

using namespace std;

int r[

2000000];

string s;

inthw()

int id=

0,mx=

0,ans =1;

for(

int i=

1;ilength()

;i++

) ans =

max(ans,r[i]-1

);}return ans;

}int

main()

演算法比較簡單,到這裡就結束了,交一發

完美ac,開心的去吃飯

O n 時間求 最長回文子串 Manacher演算法

回文字串分為奇回文和偶回文,在字串中間插入任意字元使得串變成奇回文串 暴力思想 肯定是找乙個點往兩邊任意擴充套件,遍歷一次,manacher時間為o n 開乙個陣列p記錄 以點i為中點 的最長回文串的半徑,假設前i 1個點的p都已經求出來來,現在考慮p i 如何推導 重點 r是p 1 p i 1 中...

Manacher 最長回文子串

最長回文子串問題 給定乙個字串,求它的最長回文子串長度。如果乙個字串正著讀和反著讀是一樣的,那它就是回文串。下面是一些回文串的例項 12321 a aba abba aaaa tattarrattat 牛津英語詞典中最長的回文單詞 對於最長回文子串問題,最簡單粗暴的辦法是 找到字串的所有子串,遍歷每...

Manacher 最長回文子串

caioj任意門 hz2016評測傳送門 可以的話來一下hz2016評測吧,有的題caioj沒有的我也可以給到資料嘛。include include include include include include include include define maxchar 100000 defin...