您的位置:首页 > 其它

manacher算法讲解

2016-02-21 21:02 183 查看
一.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#
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  acm 算法 manacher