manacher算法讲解

一.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]

manacher算法讲解_第1张图片

由图可知,以id为中心,向右到mx是回文串,所以两侧是对称的,因为当p[i] = p[j]时,也未超过mx的大小,所以p[i]一定 == p[j] (如果p[i] > p[j]根据对称,p[j]就就应该变大)

当mx - i  <= p[j]

manacher算法讲解_第2张图片

这种时候需要对大于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#

你可能感兴趣的:(manacher算法讲解)