在介紹演算法之前,首先介紹一下什麼是回文串,所謂回文串,簡單來說就是正著讀和反著讀都是一樣的字串,比如abba,noon等等,乙個字串的最長回文子串即為這個字串的子串中,是回文串的最長的那個。
一.通常解決的問題
給定乙個字串,求出其最長回文子串。例如:
(1)s="abcd", 最長回文長度為 1;
(2)s="ababa", 最長回文長度為 5;
(3)s="abccb", 最長回文長度為 4,即 bccb。
經典例題:hdu3068
以上問題的傳統思路大概是,遍歷每乙個字元,以該字元為中點向兩邊查詢。其時間複雜度為 o(n2),很不高效。而在 1975 年,乙個叫 manacher 的人發明了乙個演算法,manacher 演算法,也稱馬拉車演算法,該演算法可以把時間複雜度提公升到 o(n)。下面來看看馬拉車演算法是如何工作的。
二.演算法原理
奇偶變換:為處理字串方便,現將給定的任意字串進行處理,使所有可能的奇數/偶數長度的回文子串都轉換成了奇數長度。具體就是在每個字元的兩邊都插入乙個特殊的符號。比如hhjj變成 #h#h#j#j#, aba變成 #a#b#a#;為防止陣列越界,可以在字串的開始加入另乙個特殊字元,比如「?#a#b#a#?」 。
定義乙個輔助陣列int p
,p[i]
表示以s_new[i]
為中心的最長回文的半徑,例如:i0
1234
5678
9101112
1314
1516
1718
19s_new[i]$#
a#b#
b#a#
h#o#
p#x#
p#p[i]12
1452
1212
1212
1612
1 可以看出,p[i]-1
正好是原字串中最長回文串的長度。
manacher 演算法之所以快,就快在對 p 陣列的求法上有個捷徑,看下圖:
設定兩個變數,mx 和 id 。
mx 代表以s_new[id]
為中心的最長回文最右邊界,也就是mx=id+p[id]
。
假設我們現在求p[i]
,也就是以s_new[i]
為中心的最長回文半徑,如果i2 * id -i
其實就是等於 j ,p[j]
表示以s_new[j]
為中心的最長回文半徑,見上圖,因為 i 和 j 關於 id 對稱,我們利用p[j]
來加快查詢。
#include#include#include#includeusing namespace std;
const int maxn=111111;
char s[maxn];
char s_new[maxn*2];
int p[maxn*2];
int init()
s_new[j] = '\0';
//printf("%s\n",s_new);
return j; //返回s_new的長度
}int manacher()
maxlen = max(maxlen, p[i] - 1);
// printf("%d %d %d\n",mx,id,maxlen);
}/*for(int i=1;i<=len;i++)printf("%d ",p[i]);
printf("\n");*/
return maxlen;
}int main()
manacher演算法(最長回文串)
題目解釋 子串 小於等於原字串長度由原字串中任意個連續字元組成的子串行 回文 關於中間字元對稱的文法,即 aba 單核 cabbac 雙核 等 最長回文子串 1.尋找回文子串 2.該子串是回文子串中長度最長的。首先要知道這個演算法是用來在o n 的時間裡看乙個字串的最長回文子串的長度是什麼。其次,它...
Manacher演算法 最長回文串
若字串長度為n,則演算法的時間複雜度為o n 假設有乙個字串abaaba 先把該字串變成 a b a a b a 第乙個字元設為 防止計算的時候陣列越界 再計算p陣列,先給出p陣列的答案 i為座標,ma陣列放改變後的字串,p陣列代表以該字元為中心,向右和向左延伸p i 個,是回文串 i 0 1 2 ...
最長回文字串(manacher演算法)
資料 網路 參見 問題描述 輸入乙個字串,求出其中最大的回文子串。子串的含義是 在原串中連續出現的字串片段。回文的含義是 正著看和倒著看相同,如abba和yyxyy。解析 這裡介紹o n 回文子串 manacher 演算法 演算法基本要點 首先用乙個非常巧妙的方式,將所有可能的奇數 偶數長度的回文子...