码迷,mamicode.com
首页 > 编程语言 > 详细

Manacher算法+注释

时间:2019-11-03 16:26:21      阅读:65      评论:0      收藏:0      [点我收藏+]

标签:知识   names   a*   print   str   表示   回文   class   while   

Manacher算法是用来求一个字符串中最长回文串的算法。

考虑暴力求最长回文串的做法:

暴力枚举字符串中的所有字串判断是否回文,然后求最大值。

时间复杂度O(n^3),考虑优化。

我们从枚举所有字串改成枚举所有回文串的对称轴,向左右扩展直到不相等,得到最长回文串。

优化到O(n^2),还是不够优秀。

于是我们引出Manacher算法。

先向字符串s中插入特殊字符得到字符串str,这样我们就不用讨论字符串长度是奇是偶了。

用一个辅助数组p表示每个点可以扩展出去的最长回文长度

从str[1]扫到str[strlen(str)],再设置两个变量mr表示已触及的最右边的字符,mid表示包含mr的回文串的对称轴位置。

当i属于(mid,mr)时,显然i关于mid的对称点是(mid<<1)-i(中点坐标公式简单推一下),由于回文串对称串的全等性,我们令p[i]=p[(mid<<1)-i],然后接着尝试扩展:str[i+p[i]]==str[i-p[i]](前后是否对称),p[i]++

若i>mid,我们就设置mid=i,mr=当前扩展到的最右字符。

给出代码结束本篇博客

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int data=0,w=1;char ch=0;
    while(ch!=- && (ch<0||ch>9))ch=getchar();
    if(ch==-)w=-1,ch=getchar();
    while(ch>=0 && ch<=9)data=data*10+ch-0,ch=getchar();
    return data*w;
}
const int maxn=5e7+10;
int n,p[maxn],ans;
char s[maxn],str[maxn];
void init(){
    str[0]=str[1]=$;//ccf喜欢这个 
    for(int i=0;i<n;i++)
        str[(i<<1)+2]=s[i],str[(i<<1)+3]=$;
    n=(n<<1)+2;
    str[n]=0;
}
void Manacher(){
    int mr=0,mid;
    for(int i=1;i<n;i++){
        if(i<mr)
            p[i]=min(p[(mid<<1)-i],p[mid]+mid-i);
        else p[i]=1;
        for(;str[i+p[i]]==str[i-p[i]];p[i]++)
        if(i+p[i]>mr)
            mr=p[i]+i,mid=i;
    }
}
int main(){
    scanf("%s",s);
    n=strlen(s);
    init();Manacher();
    ans=0;
    for(int i=0;i<n;i++)
        ans=max(ans,p[i]);
    printf("%d\n",ans-1);
    return 0;
}

下一篇更新一些数论知识

Manacher算法+注释

标签:知识   names   a*   print   str   表示   回文   class   while   

原文地址:https://www.cnblogs.com/light-house/p/11787641.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!