最长回文(Manacher)

最长回文

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 12244    Accepted Submission(s): 4501


Problem Description
给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
回文就是正反读都是一样的字符串,如aba, abba等
 
Input
输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c...y,z组成的字符串S
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000
 
Output
每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度.
 
Sample Input
aaaa abab
 
Sample Output
4 3
 题解:manacher算法:可以求出字符串每个位置的最长字串;

if( mx > i)
    p[i]=MIN( p[2*id-i], mx-i);

就是当前面比较的最远长度mx>i的时候,Pi]有一个最小值。这个算法的核心思想就在这里,为什么P数组满足这样一个性质呢?
   (下面的部分为图片形式)


代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#define mem(x,y) memset(x,y,sizeof(x))
using namespace std;
typedef long long LL;
const int INF=0x3f3f3f3f;
const int MAXN=250005;
int p[MAXN];
char str[MAXN],s[MAXN];
int Manacher(char *s,int len){
    mem(p,0);
    p[0]=p[1]=1;
    int id=1,mx=1;
    int ans=0;
    for(int i=2;i<len;i++){
       if(mx>i)p[i]=min(p[2*id-i],mx-i);//这句不加会超时,是一个优化 
        //找对称轴左侧这个地方和最大值地方的长度大小,找小的 
        else 
		p[i]=1;
        while(s[i-p[i]]==s[i+p[i]])p[i]++;
        if(p[i]+i>mx)mx=p[i]+i,id=i;//更新对称轴id,更新右侧匹配的最大值mx 
        ans=max(ans,p[i]);
    }
    return ans-1;
}
int main(){
    int flot=0;
    while(~scanf("%s",str)){
        int len=strlen(str);
        s[0]='@';
        for(int i=0;i<len;i++){
            s[2*i+1]='#';
            s[2*i+2]=str[i];
        }
        s[2*len+1]='#';
    //    if(flot++)puts("");
        printf("%d
",Manacher(s,2*len+2));
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/handsomecui/p/4908954.html