一.manacher算法求出的是什么?
mancher算法求解出一个字符串中,以每一个字符为中心的回文的最长长度。复杂度是o(n)
二.manacher算法是如何实现的?
1.首先需要对一个字符串进行预处理
设原字符串为t,处理得到的字符串为s。为了字符串从零开始,另字符串s[0] = ‘&’(为保证与之后的字符都不相同)
然后分别在开头,每个字符之间,以及最后,添加一个与t中字符都不同的字符,一般为‘#’
那么为什么要进行预处理呢?使得长度为奇数和偶数回文串都变成长度为偶数的字符串。
2.求解以每个字符为中心,回文的最长长度
首先我们假设i之前的回文长度都已经求出了。以i为中心的回文串的长度用P[i]存储。P[i] -1就是该回文子串在原串中的长度(包括‘#’)最远匹配到(从一个位置id开始,两侧字符相等的最远位置)的字符串的位置为mx,使得位置最远的回文串是以id为中心的。
下面是该算法的关键
if(mx > i) p[i] = min(mx - i,p[2 * id - i])
下面图片来自:http://www.cnblogs.com/biyeymyhjob/archive/2012/10/04/2711527.html
当mx - i > p [j]
由图可知,以id为中心,向右到mx是回文串,所以两侧是对称的,因为当p[i] = p[j]时,也未超过mx的大小,所以p[i]一定 == p[j] (如果p[i] > p[j]根据对称,p[j]就就应该变大)
当mx - i <= p[j]
这种时候需要对大于mx的地方进行匹配
ps:如果mx <= i,还没匹配到这里的时候要对p[i] 初始化为1,要从头开始匹配
下面是manacher算法的代码
预处理:
void init()
{
s[0] = '&';
for(int i = 0; i < n; i ++)
{
s[i * 2 + 2] = t[i];
s[i * 2 + 1] = '#';
}
s[n * 2 +1] = '#';
}
void gethuiwen()
{
int mx = 0,id = 0;
for(int i = 1; i < n * 2 + 2;i ++)
{
if(mx > i)
{
p[i] = min(p[id * 2 - i],mx - i);
}
else
p[i] = 1;
for(;s[p[i] + i] == s[i - p[i]];p[i] ++);
if(p[i] + i > mx)
{
mx = p[i] + i;
id = i;
}
}
}
//#a#a#a#a#