原文出處:http://www.cnblogs.com/grandyang/p/4475985.html
manache算法俗稱馬拉車算法,該算法的作用是求一個字符串中的最大回文子串,例如"11123321"。
馬拉車算法找回文串的方法是從中間往左右兩邊找,但是這樣找就會遇到幾個問題;第一個,比如"1221",馬拉車算法就不好找(所以會用到預處理);第二個這樣暴力找的時間開銷大,所以會用一個p數組來記錄一下包括了當前能夠形成迴文串的最大回文半徑(迴文串字符數量的一半,這裏的一半肯定整數,不會出現小數,原因請看預處理),來快速跳轉找當前迴文串的一個可能大小(因爲後面可能會增大,但一定不會減小),舉個栗子,如下圖:
因爲一個以id爲中心的迴文串中的兩邊個對稱的迴文串(一個以2*id-1爲中心的迴文串,另一個以i爲中心的迴文串是相等的)所以:
當2*mx-i<=p[2*id-i]時,
當2*mx-i>p[2*id-i]時,
- 預處理
將輸入的字符在每一個字符的兩邊加上一個"#"(其他符號也行,必須與輸入的字符不一樣),在一個字符前面加個"*"(其他符號也行,不能和輸入字符或者"#"一樣),例如:
"11123321" -> "*#1#1#1#2#3#3#2#1#"
加"#"的原因:可以將每一個原字符子串變成一個奇數個數的子串,保證每個子串是一字符爲中心的串,如果不是以一個字符爲中心的串,在求一個迴文串時只能去一個字符一個字符擴展後再去判斷。
加"*":提供非迴文(結束迴文擴展操作,防止溢出,出現s[-1]的情況)。
題目地址:https://ac.nowcoder.com/acm/contest/549/B
code:
/*
馬拉車算法manacher
*/
#include<bits/stdc++.h>
using namespace std;
const int mn=10005;
int p[mn*2],id,mx;
string s;
void manache(string t){
int i,j;
s.clear();
s+="*#";
for(i=0;i<2*t.size();i++){
s+=t[i%t.size()];
s+="#";
}
// cout<<s<<endl;
int maxl=0;
memset(p,0,sizeof p);
for(i=0;i<s.size();++i){
p[i]=mx>i?min(p[2*id-i],mx-i):1;
while(s[i-p[i]]==s[i+p[i]]&&(p[i]-1<s.size()/4)) ++p[i];
if(mx<p[i]+i){
mx=i+p[i];
id=i;
}
// cout<<p[i]<<' '<<i<<endl;
maxl=max(maxl,p[i]);
}
cout<<maxl-1<<endl;
}
int main(){
string t;
while(cin>>t){
manache(t);
}
return 0;
}
如果還是看不懂的話,請看原文博客,圖片畫的灰常具體!!