Manacher算法,又叫“马拉车”,它可以在时间复杂度和空间复杂度都是O(n)的情况下,求出一个字符串的最长回文串长度。
通过优化朴素诞生的一个算法
首先将字符拓展为固定形式例如abc拓展为:abc -> #a#b#c ->@#a#b#c%(@#%需为不存在的字符)
然后就可以去除奇偶性,遍历字符进行回文拓展
需要通过一个数组存储每个字符的最大回文长度
主要依托回文的特性来优化朴素算法
图片来自:马拉车算法 | Coding Club
在a的超大回文中,可以直接将左侧回文的复制到右侧,通过这种方法来优化朴素算法
主要分为三部
1,变换字符串:abc -> #a#b#c ->@#a#b#c%(@#%需为不存在的字符)
2,用R和Mid记录目前最右侧的边界和中心
例如:
3,遍历字符串
1》给p[i]赋初值:如果在最大的内部:
如果对称的范围不超过边界,就直接复制
如果超过边界,就赋值为距离边界的距离
如果不在内部:直接赋值为1(朴素算法)
2》向两端拓展直到最大
3》如果拓展后的边界大于R,就迭代R和Mid
4,最后将p里的数字减去1然后除以二((p[i]-1)/2)后就是该位置最大的回文长度了
注意:因为字符串初始化的时候头尾不一致,所以能自动结束
#include <bits/stdc++.h>
using namespace std;
string change(string s)
{
string res = "@#";
for(char c : s){res += c; res += "#";}
res += "#$";
return res;
}
void Manacher(string s,int *p)
{
int R = 0,Mid = 0;
for(int i = 0;i < s.size();++i)
{
p[i] = R > i ? min(p[2 * Mid - i],R-i) : 1;//给p[i]赋初值
while(s[p[i] + i] == s[i - p[i]]) ++p[i];//向两端拓展直到最大
if(p[i] + i > R)//如果拓展后边界大于R,就迭代R和Mid
{
Mid = i;
R = p[i] + i;
}
}
}
int main()
{
string s;
cin >> s;
s = change(s);
int p[s.size()];
Manacher(s,p);
return 0;
}