最長回文子串 輕鬆理解Manacher演算法

2021-08-07 19:49:58 字數 1811 閱讀 2048

最長回文子串這個問題的manacher演算法,看了很多部落格,好不容易理解了,做一下記錄。

這個演算法的核心就是:將已經查詢過的子字串的最右端下標儲存下來,在計算下標為i的回文字串時,不需要從左右相鄰的地方開始比較遍歷,而是從某個初始值開始。

那麼求這個初值就是該演算法的關鍵。

先將字串的每兩個字元之間插入識別符號,如「#」,然後在頭尾也插入,插入什麼符號這個其實影響不大。我是在頭部和尾部也插入的「#」。這一步是為了讓對稱軸都在字串陣列中。

例項字串  abada --> #a#b#a#d#a# 

下標i從1 ~ length-1 開始遍歷。同時借助2個輔助量 mid 和 maxright ,maxright 是用來儲存我們掃瞄過的字串的最右端的下標。mid為掃瞄最右端時的對稱軸下標。注意,最右端的回文串不一定是最長的回文串。我們只是用maxright來標識掃瞄長度。

我們用p[i]來儲存回文字串的單邊長度。即以下標i的字元為對稱軸的回文串的最右端與i的差值+1。回文串長度/2+1。

示例:  

注意:maxright對應下標時需要-1去對應。因為每次從center開始擴張時,結束條件是maxright時center不能成為回文中心。

核心**為這一句:

p[i] = maxright > i ? math.min(p[2*center-i],maxright-i) : 1 ;
可能這樣比較難以理解。我們可以結合以上的例子,來慢慢分析。

str[center] - str[maxright-1]為我們的最右端回文字串。我們維護這個字串的位置。

當我們處理str[i]這個字元的回文長度時。

1

if ( maxright >i)else

22 }else

上面的核心分析過程簡化後就是上面的那一行**。

核心**理解了,後續的就簡單了,從p[i]的初始值開始,向左右擴張,判斷左右邊界是不是相等,並同時更新center和maxright的值。最後掃瞄p陣列,其中最大的就是回文子串的長度,下標就是擴充了#的字串下標。

最後,貼上源**,大家看一看就可以理解了。

1

public

static

string longestpalindrome(string s)

9int center = 0 ,maxright = 0 ,len =builder.length();

10int p = new

int[len];

11for (int i = 1; i < len-1; i++)

20//

更新maxright center

21if ( i + p[i] >maxright)25}

26//

遍歷p陣列求極大值

27int mid= 0 , maxlength = 0;

28for (int i = 1; i < builder.length(); i++) 33}

34//

分割字串,消去"#"

35return builder.tostring().substring(mid-maxlength+1,mid+maxlength-1).replace("#","");

36 }

最長回文子串 輕鬆理解Manacher演算法

最長回文子串這個問題的manacher演算法,看了很多部落格,好不容易理解了,做一下記錄。這個演算法的核心就是 將已經查詢過的子字串的最右端下標儲存下來,在計算下標為i的回文字串時,不需要從左右相鄰的地方開始比較遍歷,而是從某個初始值開始。那麼求這個初值就是該演算法的關鍵。先將字串的每兩個字元之間插...

最長回文子串 最長回文子串行

1.最長回文子串行 可以不連續 include include include include using namespace std 遞迴方法,求解最長回文子串行 intlps char str,int i,int j intmain include include include using n...

最長回文子串

描述 輸入乙個字串,求出其中最長的回文子串。子串的含義是 在原串連續出現的字串片段。回文的含義是 正著看和倒著看是相同的,如abba和abbebba。在判斷是要求忽略所有的標點和空格,且忽略大小寫,但輸出時按原樣輸出 首尾不要輸出多餘的字串 輸入字串長度大於等於1小於等於5000,且單獨佔一行 如果...