Manacher算法求解最长回文串
推荐的参考博文
根据博主的介绍,我写出了下面的C++代码
#include<bits/stdc++.h>
using namespace std;
string Pre(string s)
{//将s转化成ManacherString
int lenth = s.size();
string line="#";
for(int i=0;i<lenth;i++)
{
line+=s[i];
line+="#";
}
return line;
}
string Manacher(string aim)
{
aim = Pre(aim);//字符串预处理
int lenth = aim.size();
int* temp = new int[lenth];
for(int i=0;i<lenth;i++)temp[i]=1;//初始化回文半径数组
//下面是核心代码
int p=0,C=-1,R=-1;//p当前访问字符,C最右回文边界的对称中心,R最右回文边界
while(p<lenth)
{
if(p>R)//要移动的位置p在R的右侧
{
int s = p;
while(s<lenth&&2*p-s>=0&&aim[s]==aim[2*p-s])s++;//以p为中心向两侧扩张
C=p;R=s-1;temp[p]=s-p;
}
else// if(p<=R) 第二种情形:要移动的位置p不在R的右侧
{
int p2 = 2*C-p;//p2是p1以C为对称中心的对称点
int cL = 2*C-R;//cL是以C为对称中心的回文子串的左边界
int pL = p2-temp[p2]+1;//pL是以p2为对称中心的回文子串的左边界
//第二情形的三种情况
if(cL==pL)
{
int s = R;
while(2*p-s>=0&&s<lenth&&aim[s]==aim[2*p-s])s++;
C=p;R=s-1;temp[p]=s-p;
}
else temp[p] = (cL<pL)? temp[p2]:(R-p+1);
}
p++;//千万不要忘了这个
}//while
//下面查找答案
int maxnum = -1;
int maxp=-1;
string ans="";//用于存储将要返回的最长回文串
//下面检测最长回文串的中心
for(int i=0;i<lenth;i++)
{
if(temp[i]>maxnum)
{
maxnum = temp[i];
maxp = i;
}
}
for(int i=maxp-maxnum+1;i<maxp+maxnum;i++)
{//整理最长回文串
if(aim[i]!='#')ans+=aim[i];
}
delete[] temp;//删除长度记录数组
return ans;
}
int main()
{
string aim = "acbbcbds";
cout<<Manacher(aim)<<endl;
return 0;
}//输出的是cbbc
先不要急着抄写,下面我们对核心代码进行压缩并使其模板化
string Pre(string s)
{//将s转化成ManacherString
int lenth = s.size();
string line="#";
for(int i=0;i<lenth;i++)
{
line+=s[i];
line+="#";
}
return line;
}
int NormalExtend(int center,int lenth,string& aim,int& C,int& R)
{//对称中心center,字符串长度lenth,字符串引用aim,最右回文边界的对称中心C,最右回文边界R
int s = max(center,R);
while(s<lenth && 2*center-s>=0 && aim[s]==aim[2*center-s]) s++;
C=center;
R=s-1;
return s-center;//该值会被赋给标记数组temp[center]
}
string Manacher(string aim)
{
aim = Pre(aim);//字符串预处理
int lenth = aim.size();
int* temp = new int[lenth];
for(int i=0;i<lenth;i++)temp[i]=1;//初始化回文半径数组
//下面是核心代码的压缩版本
int p=0,C=-1,R=-1;//p当前访问字符,C最右回文边界的对称中心,R最右回文边界
while(p<lenth)
{
int p2 = 2*C-p;//p2是p1以C为对称中心的对称点
int cL = 2*C-R;//cL是以C为对称中心的回文子串的左边界
int pL = p2-temp[p2]+1;//pL是以p2为对称中心的回文子串的左边界
if(p>R || (p<=R&&cL==pL)) temp[p] = NormalExtend(p,lenth,aim,C,R);
else temp[p] = (cL<pL)? temp[p2]:(R-p+1);
p++;
}
//下面查找答案
int maxnum = -1;
int maxp=-1;
string ans="";//用于存储将要返回的最长回文串
//下面检测最长回文串的中心
for(int i=0;i<lenth;i++)
{
if(temp[i]>maxnum)
{
maxnum = temp[i];
maxp = i;
}
}
for(int i=maxp-maxnum+1;i<maxp+maxnum;i++)
{//整理最长回文串
if(aim[i]!='#')ans+=aim[i];
}
delete[] temp;//删除长度记录数组
return ans;
}
OK