manacher马拉车算法
manacher算法
用于快速求解字符串中的最长回文子串
数组 p: p[i]表示以字符t[i]为半径的回文子串长度
规律:
- 最大半径减 1 等于最长回文串的长度
- 最长回文字符的起始位置是中间位置减去半径在除以 2
对于模板
首先预处理数组s得到数组t
再从1到n遍历更新 $p[i]=mx>i ? min(mx-i,p[(id<<1)-i]) : 1 $
再对于每个p[i]暴力扩展两边实现最大
之后统计mx,id,maxl,maxp
最终输出最长回文子串
模板
manacher 带注释
string manacher(string s)
{
//预处理s,方便计算p数组,此处仅前+'$',中和后+'#'
string t="$#";
for(auto a:s){
t+=a;
t+='#';
}
//下面开始p数组的求解
//mx和id为所有已经求得的回文串的右端点的最大值和中心点,初始默认为0
//maxl与maxp统计最大的回文子串的长度和开始位置
vector<int> p(t.size()+5,0);
int mx=0,id=0,maxl=0,maxp=0;
for(int i=1;i<t.size();++i){
//利用已经维护的数组p[1~i-1]的值先一步更新p[i]的大小
p[i]=mx>i ? min(mx-i,p[(id<<1)-i]) : 1 ;
//中心扩展法更新最大值
while(t[i+p[i]]==t[i-p[i]]) ++p[i];
//更新mx与id
if(i+p[i]>mx){
mx=i+p[i];
id=i;
}
//更新最大回文子串
if(p[i]>maxl){
maxl=p[i];
maxp=(i-p[i])/2;
}
}
return s.substr(maxp,maxl-1);
}
manacher 无注释
string manacher(string s)
{
string t="$#";
for(auto a:s){
t+=a;
t+='#';
}
vector<int> p(t.size()+5,0);
int mx=0,id=0,maxl=0,maxp=0;
for(int i=1;i<t.size();++i){
p[i]=mx>i ? min(mx-i,p[(id<<1)-i]) : 1 ;
while(t[i+p[i]]==t[i-p[i]]) ++p[i];
if(i+p[i]>mx){
mx=i+p[i];
id=i;
}
if(p[i]>maxl){
maxl=p[i];
maxp=(i-p[i])/2;
}
}
return s.substr(maxp,maxl-1);
}
例题
板子题
hdu 3068
洛谷 P3805
ABC 320 B - Longest Palindrome