#1032 : 最長回文子串
時間限制:1000ms
單點時限:1000ms
記憶體限制:64mb
描述:小hi和小ho是一對好朋友,出生在資訊化社會的他們對程式設計產生了莫大的興趣,他們約定好互相幫助,在程式設計的學習道路上一同前進。
這一天,他們遇到了一連串的字串,於是小hi就向小ho提出了那個經典的問題:「小ho,你能不能分別在這些字串中找到它們每乙個的最長回文子串呢?」
小ho奇怪的問道:「什麼叫做最長回文子串呢?」
小hi回答道:「乙個字串中連續的一段就是這個字串的子串,而回文串指的是12421這種從前往後讀和從後往前讀一模一樣的字串,所以最長回文子串的意思就是這個字串中最長的身為回文串的子串啦~」
小ho道:「原來如此!那麼我該怎麼得到這些字串呢?我又應該怎麼告訴你我所計算出的最長回文子串呢?
小hi笑著說道:「這個很容易啦,你只需要寫乙個程式,先從標準輸入讀取乙個整數n(n<=30),代表我給你的字串的個數,然後接下來的就是我要給你的那n個字串(字串長度<=10^6)啦。而你要告訴我你的答案的話,只要將你計算出的最長回文子串的長度按照我給你的順序依次輸出到標準輸出就可以了!你看這就是乙個例子。」
首先用乙個非常巧妙的方式,將所有可能的奇數/偶數長度的回文子串都轉換成了奇數長度:在每個字元的兩邊都插入乙個特殊的符號。比如 abba 變成 #a#b#b#a#, aba變成 #a#b#a#。 為了進一步減少編碼的複雜度,可以在字串的開始加入另乙個特殊字元,這樣就不用特殊處理越界問題,比如$#a#b#a#。
下面以字串12212321為例,經過上一步,變成了 s = "$#1#2#2#1#2#3#2#1#";
然後用乙個陣列 p[i] 來記錄以字元s[i]為中心的最長回文子串向左/右擴張的長度(包括s[i],也就是把該回文串「對折」以後的長度),比如s和p的對應關係:
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 1
p[3]=2也正好是原始串s中以2為中心的回文串的總長度,即回文串122的長度為3.
所以我們只需要求出陣列p,然後求p中的最大值即為s中最長回文串的長度。
那麼怎麼計算p[i]呢?該演算法增加兩個輔助變數(其實乙個就夠了,兩個更清晰)id和mx,其中id表示最大回文子串中心的位置,mx則為id+p[id],也就是最大回文子串的邊界。
然後可以得到乙個非常神奇的結論,這個演算法的關鍵點就在這裡了:如果mx > i,那麼p[i] >= min(p[2 * id - i], mx - i)。就是這個串卡了我非常久。實際上如果把它寫得複雜一點,理解起來會簡單很多:
//記j = 2 * id - i,也就是說 j 是 i 關於 id 的對稱點。
if (mx - i > p[j])
p[i] = p[j];
else /* p[j] >= mx - i */
p[i] = mx - i; // p[i] >= mx - i,取最小值,之後再匹配更新。
借助[圖來理解]
1/*2view code****************************最長回文子串(mancher)*************************************
3******************************by ja/c++ 2015-1-16****************************************4*/
56 #include7 #include
8 #include9
10using
namespace
std;
1112
string preprocess(string
s) 22
23int longestpalindrome(string
s) 43}44
45//
find the maximum element in p.
46int maxlen = 0;47
//int centerindex = 0;
48for (int i = 1; i < n - 1; i++) 53}
54delete p;
5556
//return s.substr((centerindex - 1 - maxlen) / 2, maxlen);
57return
maxlen;58}
5960
intmain()
6170 }
1.beeder's blog 《最長回文子串》
2.leetcode 《longest palindromic substring》
3.ddyyxx的程式設計師之路 《manacher演算法總結》
最長回文子串 最長回文子串行
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,且單獨佔一行 如果...
最長回文子串
輸入乙個字元,求出其中最長的回文子串。子串的含義是 在元串中連續出現的字串片段。回文的含義是 正看和倒看相同,如abba和yyxyy,在判斷時候應該忽略所有的空格和標點符號,且忽略大小寫,但輸出應該保持原樣,輸入的字元長度不超過5000,且佔據單獨一行,輸出最長的回文子串 如有多個,輸出,起始位置最...