回文串 Manacher's Algorithm

今天刚学了Manacher算法,也就是马拉车算法,是用来查找一个字符串中的回文串的算法,算法复杂度是线性的,比朴素的暴力求解快很多。

一、预处理

对于一个字符串,要找它的回文串,首先想到的就是从头到尾一个个找过来,而且回文串存在两种情况,一种是长度为奇数的回文串,还有一种是长度为偶数的回文串。所以每次循环到一个位置,都要分奇偶回文串进行查找,很麻烦。
比如对于字符串:adccbcc 循环到字符c的时候存在一个长度为2的偶数长回文串"cc",而循环到b的位置的时候存在一个长度为5的奇数长度的回文串"ccbcc"。
我们可以先在字串的前后和每两个字符中间插入一个没有出现过的字符,比如上面的那个字符串,插入’#'预处理之后就变成了,#a#d#c#c#b#c#c#。处理之后的字符串肯定是个奇数串,只用查找奇数回文串就好了。

二、算法实现

对于朴素算法,比如字符串T =“a d c a c d c a c d b d”对于每个位置都要查询一遍,而马拉车算法在朴素地算法上增加了一部分的剪枝,如果已经知道T[5]的位置存在回文串 “dcacdcacd” 而且知道了T[5]之前的每个位置的回文串的长度,由于奇数长度的回文串对于中心堆成,那么T[7]位置的回文串“cac”在之前T[3]的位置已经出现过了,所以可以直接得出T[7]位置的回文串的长度为3并且和T[3]处的回文串相同。
我们需要记录回文串的结尾下标最靠右(把最右端称为右界)的那个回文串中心字符的下标md,还有以每个位置为中心开始的回文串的长度+1的一半(也就是回文串的半边长度加上中间位置),用数组P来记录。

接下来分两种情况讨论:
①:查询点的下标小于右界,又可以分两种小case:
1、查询点的下标加上对称点的回文串半边长度小于右界 这时直接把对称点回文串的长度赋值给查询点就行了。
2、查询点下标加上对称点的回文串半边长度大于等于右界 这时在右界之前的回文串长度已知,对右界及之后的点进行匹配直到失配,更新md下标。
②:查询点下标大于右界:
这种情况下,只可能查询点下标比右界大1,按朴素的办法进行匹配就好了,然后更新md下标。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1e4+7;
char in[maxn],text[maxn];
int P[maxn];
void pre_treat(){
    int len = strlen(in);
    for(int i=0;i<len;i++){
        text[i*2] = '#';
        text[i*2+1] = in[i];
    }
    text[len*2]='#';text[len*2+1]='\0';
}
void manacher(){
    P[0] = 1;                                   //第一个字符的回文串肯定是1
    int len = strlen(text);
    int md = 0;
    for(int i=1;i<len;i++){
        if(i<md+P[md]){
            int k = P[md*2-i];                  //找到对称点的回文串长度
            if(i+k<md+P[md]) P[i] = k;          //回文串没有超过右界
            else{
                k = md+P[md]-i;
                while(i+k<len&&i+k>=0&&text[i+k]==text[i-k]) k++;
                md = i;
                P[i] = k;
            }
        }
        else{
            int k = 1;
            while(i+k<len&&i+k>=0&&text[i+k]==text[i-k]) k++;
            md = i;
            P[i] = k;
        }
    }
    for(int i=0;i<len;i++) printf("%d ",P[i]);      //(处理之后的每个点的回文串的长度)/2+1
}
int main(){
    scanf("%s",in);
    pre_treat();
    manacher();
}

猜你喜欢

转载自blog.csdn.net/qq_43710979/article/details/89055092