最長回文子串這個問題的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陣列,其中最大的就是回文子串的長度,下標就是擴充了#的字串下標。
最後,貼上源**,大家看一看就可以理解了。
1public
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,且單獨佔一行 如果...