GDOI市选出了一道关于Manacher的题目,于是打算学一下,但因为网络流鸽了一阵,最近才学完,学完后表示复杂度有点迷。
Manacher算法简介
Manacher,俗称马拉车,是由一位名叫Manacher的人与1975年提出的,这个算法让求最长回文子串的复杂度从O(n^2)下降到了O(n)。
Manacher的思想
先从n方算法说起,n方算法是每一位都向两边扩展,直到不回文。这个算法只是对当前位置进行操作,而Manacher算法将前面算出的值进行记录,用于后续的处理,从而降低复杂度。
我们平时用n^2算法处理的时候就会考虑到一个问题,就是一个回文串的长度,如果是像aaa一样的长度为奇数的串,它的中心是一个字符;如果是像abba一样长度为偶数的串,它的中心在两个字符中间,这样比较难处理。所以Manacher算法会在一个字符串每两个字符中间以及字符串头尾插入‘#’(也可以是其他的,有没有出现在原字符串中其实无所谓)。
如:abcdcba会变为#a#b#c#d#c#b#a#。
这里我们引入一个数组p[],p[i]表示以i为中心的最长回文串的半径长度。我们用表格举个例子:
s | # | a | # | b | # | a | # | b | # | a | # | b | # | a | # |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
p | 1 | 2 | 1 | 4 | 1 | 6 | 1 | 8 | 1 | 6 | 1 | 4 | 1 | 2 | 1 |
而更神奇的是以s[i]为中心的回文串长度就是p[i]-1。
Manacher的实现
我们需要记录的除了p数组,还有在现在已知(即之前处理过的)的所有回文串中右边界最右的那个回文串c的中心位置mid以及其长度len(记录其右边界也可)。
设我们即将处理的位置为i,i关于mid的对称点为j,那么:
如果i > mid+len-1
即i在回文串c右边界的右边,没有任何先前的数据可以利用,所以p[i]=1,直接暴力求p[i]。
如果j-p[j]+1 >= mid-len+1,
即以j为中心的最长回文串(下图红色部分)在回文串c内,则以i为中心的最长回文串(下图蓝色部分)一定也在该字符串内,那么就有p[i]=p[j],如下图。
如果j-p[j]+1 < mid-len+1,
即以j为中心的最长回文串(下图红色部分)有一部分在回文串c外,则以i为中心的最长回文串(下图蓝色部分)至少有一部分可以确定(下图绿色部分),那么我们可以直接从确定的部分拓展算出p[i],这里p[i]一定小于p[j]。
代码
上面是一个理解算法的过程,事实上并不用如此复杂的操作。另外有一个小技巧,可以在字符串最前端插入一个’$’,在字符串最末端插入一个’\0’,并以此来完成对回文串边界的判断,所以插入的可以不是上述的两个字符,但是一定不能出现在原字符串中。
那么,上代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int MAXN=11000005;
char c[MAXN],s[MAXN*2+1];
int lenc,lens;
int p[MAXN*2+1],mid,len,maxlen;
int minn(int a,int b){return a>b?b:a;}
int maxx(int a,int b){return a>b?a:b;}
void init()
{
lenc=strlen(c);
s[0]='$';s[1]='#';
lens=2;
for (int i=0;i<lenc;i++)
{
s[lens++]=c[i];
s[lens++]='#';
}
s[lens++]='\0';
memset(p,0,sizeof(p));
}
int main()
{
scanf("%s",c);
init();
mid=-1;len=0;maxlen=0;
for (int i=1;i<lens;i++)
{//用mid+len作边界,和mid+len-1差不了多少,只是为了处理方便,处理时注意一下就好了
if (mid+len>i)p[i]=minn(mid+len-i,p[2*mid-i]);
else p[i]=1;//这里就是上面说的内容,给p[i]附一个初值
while (1)
{
if (s[i-p[i]]!=s[i+p[i]])break;
p[i]++;
}//虽然看上去会让算法退化但是算法优啊
if (i+p[i]>mid+len)
{
mid=i;
len=p[i];
}//更新mid和len
maxlen=maxx(maxlen,p[i]-1);
}
printf("%d",maxlen);
return (0-0);
}
来源:CSDN
作者:dddttdLALALA
链接:https://blog.csdn.net/qq_41814633/article/details/80336204