[Manacher]最长回文子串

很久没有写博客了
啪啪啪
写一些东西吧

最长回文子串怎么求呢
首先我们得知道什么是子串,给你一个长长的串,里面任意连续的一段就是它的子串,当然一个字符也是子串
接着什么是回文串呢 不好描述 但是看例子很容易懂:aba 121 1221 1
然后我们有一种很显然的寻找方法 当然是枚举中点 然后尽可能的往外扩大回文串的长度 这种算法花费的时间是N(字符串长度)*Mk(可扩展长度)Mk<N

当然这样的时间并不是很让人满意
于是Manacher这个人发明了一种新算法
他是这样想的
假如我先前已经找到的回文串已经是很大了,比如已经覆盖了整个字符串那么长
那我找到它以后 就不要找了啊 根据回文串左右对称的特性
我们可以利用之前找到的可扩展的右端,以及扩展起始点
如果当前查找的被扩展最右端覆盖,那么当前查找的起始点可扩展的最小值就是以扩展起始点为对称中心相对称的那个点的扩展值
如果扩展到了边界,就可以继续扩展下去直到不能扩展,啪啪啪就结束了

非常精彩 但是有个问题 中点可能是一个字符 也可以是两个字符
分情况讨论?费劲
有一种很机智的方法 往字符串每个字符间掺同一个不属于这个字符串的字符然后前后各掺一个
显然假如字符串有n个 新字符串必为2*n+1 也就是只需要讨论一种情况了
至于到底要求长度还是求字符 就在求的时候开个最大值记录的存一下就行了

这个算法的时间花费是4*N(字符串长度)(建一遍,找一遍,长度因为扩大了一倍所以是2N)

下面是个打得很烂的模板

//Manacher算法
string s;
char inser='&';
char str[301000];
int len[301000];
void cvt(int n){
    str[0]=inser;
    for(int i=1;i<=(n<<1);i+=2){
        str[i]=s[i>>1];
        str[i+1]=inser;//cout<<str[i]<<" "<<str[i+1]<<" ";
    }
}
void getLen(int l){
    int p0=0,p=0;len[0]=1;
    int j;
    for(int i=1;i<=l;i++){
        if(i<=p){
            j=(p0<<1)-i;
            if(len[j]<(p-i))len[i]=len[j];
            else len[i]=p-i;
//          len[i]=min(len[2*p0-i],p-i);
        }
        else
            len[i]=1;
        int cl=i-len[i],cr=i+len[i],temp=len[i];
        while(cl>=0&&cr<=l&&str[cl]==str[cr]){
        //  if(str[cr]!=inser&&str[cr]>str[cr-2])break;
            temp++;
            cl--;cr++;
        }
        len[i]=temp;
        if((i+len[i]-1)>p){
            p=i+len[i]-1;
            p0=i;
        }
    }
}
int main(){
    while(cin>>s){
        int n;
        n=s.size();
        cvt(n);
        getLen(n<<1);
        int ans=0;
        for(int i=0;i<=(n<<1);i++)
        ans=max(ans,len[i]);
        cout<<ans-1<<endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/passguan/p/9501192.html

时间: 2024-10-02 18:31:24

[Manacher]最长回文子串的相关文章

hdu 3068 最长回文(manacher&amp;最长回文子串)

最长回文 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 7317    Accepted Submission(s): 2500 Problem Description 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 回文就是正反读都是一样的字符串,如aba, abba等 Input 输入有多组

(字符串) Manacher 最长回文子串。

最长回文子串就是一个字符串的一个子串,他从左往右读和从右往左读是一样的. 可以用 Manacher 算法来求,他的复杂度是 O(n) . 可以看这篇文章 http://blog.csdn.net/ywhorizen/article/details/6629268 但是其中应该有一个错误(纠结了我一天...) 就是 这一句,文章里面是说当 Mx-i <= Mp[j] 的时候就要用到,因为后面的还没比较. 但是如图,蓝色的部分是相等的,如果红色的等于蓝色的话,那么Mx就不可能是这个值,所以红色的一定

Manacher算法----最长回文子串

题目描述 给定一个字符串,求它的最长回文子串的长度. 分析与解法 最容易想到的办法是枚举所有的子串,分别判断其是否为回文.这个思路初看起来是正确的,但却做了很多无用功,如果一个长的子串包含另一个短一些的子串,那么对子串的回文判断其实是不需要的.同时,奇数和偶数长度还要分别考虑. Manacher算法可以解决上述问题,并在O(n)时间复杂度内求出结果.下面我们来看一下Manacher算法. 首先,为了处理奇偶的问题,在每个字符的两边都插入一个特殊的符号,这样所有的奇数或偶数长度都转换为奇数长度.比

[hiho 01]最长回文子串、Manacher算法

题目描述 - 基础方法:枚举子串,判断是否为回文串. - 改进:枚举中间位置,向两侧拓展. - 再改进:利用以前的信息,使得不用每个新位置都从长度1开始拓展. - 优化:将字符串预处理为奇数长度以避免考虑条件分支. - 再优化:开头加入特殊字符避免考虑边界. Manacher 算法: id 是中心点,mx 是其边界.P[i] 表示以 i 为中心的最长回文子串的折半长度. 只要 i < mx, 以 i 为中心的回文子串就可以不必从长度1开始找,而从min{P[j], mx - i}开始(其中j为i

O(n) 求最长回文子串的 Manacher 算法

Manacher是一个可以在O(n)的时间内求出一个长度为n的字符串的算法. 以为回文子串有偶数长度,也有奇数长度,分别处理会很不方便. 所以在每两个字符中间插入一个无关字符,如‘#’,这样所有的回文子串都变为奇数长度. 两端在添加不同的无关字符防止匹配时越界. 如: abba 变成 $#a#b#b#a#& 预处理代码: void Prepare() { l = strlen(Str); S[0] = '$'; for (int i = 0; i <= l - 1; i++) { S[(i

计算字符串的最长回文子串 :Manacher算法介绍

在介绍算法之前,首先介绍一下什么是回文串,所谓回文串,简单来说就是正着读和反着读都是一样的字符串,比如abba,noon等等,一个字符串的最长回文子串即为这个字符串的子串中,是回文串的最长的那个. 计 算字符串的最长回文字串最简单的算法就是枚举该字符串的每一个子串,并且判断这个子串是否为回文串,这个算法的时间复杂度为O(n^3)的,显然无法令人 满意,稍微优化的一个算法是枚举回文串的中点,这里要分为两种情况,一种是回文串长度是奇数的情况,另一种是回文串长度是偶数的情况,枚举中点再判断是否 是回文

[hdu3068 最长回文]Manacher算法,O(N)求最长回文子串

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3068 题意:求一个字符串的最长回文子串 思路: 枚举子串的两个端点,根据回文串的定义来判断其是否是回文串并更新答案,复杂度O(N3). 枚举回文串的对称轴i,以及回文半径r,由i和r可确定一个子串,然后暴力判断即可.复杂度O(N2). 在上一步的基础上,改进判断子串是否是回文串的算法.记fi(r)=(bool)以i为对称轴半径为r的子串是回文串,fi(r)的值域为{0, 1},显然fi(r)是关于r

Manacher&#39;s algorithm: 最长回文子串算法

Manacher 算法是时间.空间复杂度都为 O(n) 的解决 Longest palindromic substring(最长回文子串)的算法.回文串是中心对称的串,比如 'abcba'.'abccba'.那么最长回文子串顾名思义,就是求一个序列中的子串中,最长的回文串.本文最后用 Python 实现算法,为了方便理解,文中出现的数学式也采用 py 的记法. 在 leetcode 上用时间复杂度 O(n**2).空间复杂度 O(1) 的算法做完这道题之后,搜了一下发现有 O(n) 的算法.可惜

【回文字符串】 最长回文子串O(N) Manacher算法

原理讲的清晰:Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串 注意: ①动态生命P[]和newStr数组后,不要忘记delete[] //其实这是基本的编码习惯 ②最终返回结果是P[i]-1 下面是自己写的Manacher函数 int manacher(char *src){ int srcLen=strlen(src); int len=2*srcLen+2; char *newStr=new char[len];//还是+3??要不要给\0留个位置??不用 i