hihoCoder 1032 最長回文子串

2021-07-10 22:29:33 字數 3159 閱讀 9131

求最長回文子串的演算法比較經典的是manacher演算法,下面寫寫自己的理解。

(文中用到的來自這裡,博主寫的很好,由於為了和**一致,我稍微p了一下。)

首先,說明一下用到的陣列和其他引數的含義:

(1)以字串中下標為

例如:字串

所以,陣列

(2)為當前已確定的邊界能伸展到最靠右的回文串的中心。

例如:

設黑色的線段表示字串範圍,紅色的線段表示當前已經確定的回文子串在主串中的範圍,雖然左邊的紅色線段(左邊的回文子串)長度比右邊長,但是,記錄的中心是右邊紅色線段的中心,因為右邊的回文子串伸展更靠右。(下面將會解釋為什麼要記錄這個id值)

manacher演算法是從左到右掃瞄的,所以,在計算

假設現在掃瞄到主串下標為為中心的回文子串。至於這個交集有什麼用,下面將解釋。

以i為中心的回文串和以id為中心的回文串如果有交集,會出現三種情況:

其中,2*id-i為i以id為中心的對稱位置。(2*id-i這個就不用多說了吧,計算一下就得到了)

第一種情況是(上圖),以2*id-i為中心的回文子串左端超出了以id為中心的回文子串(綠色部分左端超出黑色部分左端)。那麼,根據回文串的特點,知道以2*id-i為中心的兩邊橙色部分是對稱的,同樣,若以id為中心,這兩段橙色部分又對稱id右邊兩段橙色部分,所以,以i為中心的兩段橙色部分也是回文串。

這種情況下,

那麼,以i為中心的橙色部分有沒有可能更長?這是不可能的,假設還可以更長,如下:

a和b對稱,b和c對稱,c和d對稱,最終得到a和d對稱,那麼,以id為中心的回文串長度就不是下面黑色部分的長度了,而應左端加a右端加d,與已經求得的長度矛盾。

所以這種情況下

第二種情況是以2*id-i為中心的回文子串在以id為中心的回文子串內,如上圖。此時,

同樣,c和d對稱,b和c對稱,a和d對稱,得到a和b對稱,那麼以2*id-i為中心的回文子串長度就不是綠色部分的長度了,需要左端加a右端加b,與以求得的長度矛盾。

所以,這種情況下

第三種情況是,以2*id-i為中心的回文子串左端與以id為中心的回文子串的左端恰好重合。則有

所以,需要用乙個while迴圈來確定它能增加多少。while迴圈為:

while (s[i - p[i]] == s[i + p[i]])

++p[i];

也就是判斷綠色兩端(下圖淺黑色線段)是否相同,如果相同,就可以不斷增加。(理解p[i]的意思,就理解這個迴圈了)

如果沒有出現交集(上面三種情況),那麼就以i為中心點找最長回文子串(下面**中else的情況)。所以,演算法主要是利用回文串的交集來減少計算。

如果我們將上面的情況總結起來,**將非常簡潔:

if (p[id] + id - 1 >= i)//沒有超出當前邊界最右的回文串,也就是上面出現交集三種情況中的一種

p[i] = min(p[2 * id - i], p[id] + id - i);

else//如果沒有交集,就以它為中心求回文串長度

p[i] = 1;

while (s[i - p[i]] == s[i + p[i]])

++p[i];

最後,需要注意的是,上面的討論都是以某個字元為中心的回文串,比如像這樣的回文串:aabaa(長度為奇數)。但是,如果是這樣的回文串:aabbaa(長度為偶數),就沒法處理。

我們可以通過插入特殊符號(如『#』)的辦法,將字串統一為奇數長度,如aabaa變為#a#a#b#a#a#  ;同理,aabbaa變為#a#a#b#b#a#a# 

注意到,上面的**:

while (s[i - p[i]] == s[i + p[i]])

++p[i];

可能越界(超過頭或尾),我們可以通過頭尾也加入不相同的特殊符號處理,如aabaa變為$#a#a#b#a#a#@。這種辦法為什麼可行呢?我們舉個例子,還是以aabaa為例,它變成$#a#a#b#a#a#@。當i指向第乙個a時(也就是i=2),這時,s[i-1]==s[i+1];繼續比較s[i-2]≠s[i+2](也就是比較$和a),就不會超過頭。所以,就避免了越界的現象。末尾加個@也是同樣的道理。

下面是hihocoder的一道求最長回文子串的題:

我的ac**:

#include#includeint min(int a, int b)

int lps(std::string &s)

int *p = new int[new_s_len + 1];

int id = 0;//記錄已經查詢過的邊界最靠右回文串的中心

int maxlps = 1;

p[0] = 1;

for (int i = 1; i < new_s_len-1; ++i)

delete p;

return maxlps - 1;

}int main()

{ int n;

std::string s;

std::cin >> n;

while (n--)

{ std::cin >> s;

std::cout<

在插入特殊符號($ # @)時,剛開始用insert()函式,超時了,應該是不斷insert的原因。後來乾脆直接用乙個新的字串儲存處理後的字串,就通過了。



hihoCoder 1032 最長回文子串

求最長回文串的長度,一道模板題,如果大家有誰不懂這個演算法,可以到這個部落格上看一下,我感覺寫的非常好,仔細看一定能看懂。manacher演算法 include include include include using namespace std const int maxn 1000005 ch...

HihoCoder 1032 最長回文子串

華電北風吹 天津大學認知計算與應用重點實驗室 2016 06 23 題目分析 首先需要注意的是 子串 和 子串行 問題還有很多變形,如最長公共子串 子串行 最長回文子串 回文子串行 等。problem1032.cpp 定義控制台應用程式的入口點。最長回文子串 張正義 2016 04 12 inclu...

hihoCoder 1032 最長回文子串

這就是最典型的manacher演算法題,聽起來高大上,而且也很難說清楚,但是實際上並不難,就相當於數學的推理,推出乙個公式即可直接解出。題目如下 時間限制 1000ms 單點時限 1000ms 記憶體限制 64mb 描述 小hi和小ho是一對好朋友,出生在資訊化社會的他們對程式設計產生了莫大的興趣,...