原文出处: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;
}
如果还是看不懂的话,请看原文博客,图片画的灰常具体!!