POJ---3974:Palindrome【最长回文串--Manacher】

题意:

简单粗暴,求一个字符串中最长回文串的长度

总结:

说明:【my,mx】 是以 id 为中心的最长回文串,ji 关于 id 的对称点 (图是偷的)

简述manacher算法实现:

(1)字符串预处理:

'abbacd' 处理成 '#a#b#b#a#c#d#',原因如下

(2)len[i]的意义:

len[i] 表示以 s[i] 为中心最长的回文串的半径,因为枚举的是回文串的中心,所以偶数长的回文串也会有一个中心点 :'#'                                                                                                                              

(3)计算len[i]:

枚举每个点为回文串的中心点时,利用前面以id为中心且右边界mx最大的回文串,观察上图,i、j 处于回文串 id 的左右两边界内,所以 i 的左右两边和 j 的左右两边是一样的,所以在【my,mx】内len[i] = len[j],超出这个范围的就暴力判断还能否加长

(4)重新预处理:

因为涉及到暴力判断,将 'abbacd' 处理成 '{#a#b#b#a#c#d#}',首尾不一样就行,这样处理后暴力时就不用判断边界

(5)细节:

mx尽量的大,暴力的就越少,最后的答案为最大的半径 - 1 --- 规律

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MAXN = 1e6+55;
char s[MAXN],t[MAXN<<1];
int len[MAXN<<1];
int init()
{
    int k = 0;
    t[0] = '{';
    int p = strlen(s);
    for(int i = 0; i < p; ++i)
    {
        t[++k] = '#';
        t[++k] = s[i];
    }
    t[++k] = '#';
    t[++k] = '}';
    return k;
}
int manacher()
{
    int k = init();
    int mx = 0,res = 0,id = 0;
    for(int i = 1 ; i < k; ++i)
    {
        if(i < mx) len[i] = min(mx-i,len[2*id - i]);
        else len[i] = 1;
        while(t[i - len[i]] == t[i + len[i]]) len[i]++;      //超出边界暴力判断
        if(i + len[i] > mx)              //使mx尽量大
        {
            id = i;
            mx = i + len[i];
            res = max(len[i],res);
        }
    }
    return res-1;
}
int main()
{
    int cases = 1;
    while(~scanf("%s",s) && s[0] != 'E')
    {
        printf("Case %d: ",cases++);
        printf("%d\n",manacher());
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值