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

最长回文---hdu3068 (回文串 manacher 算法模板)

时间:2015-09-30 20:59:16      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3068

 

题意很清楚:就是求一个串s的子串中最长回文串的长度;这类题用到了manacher算法

 

manacher算法(复制大神的解释):

 

定义数组p[i]表示以i为中心的(包含i这个字符)回文串半径长

将字符串s从前扫到后for(int i=0;i<strlen(s);++i)来计算p[i],则最大的p[i]就是最长回文串长度,则问题是如何去求p[i]?

 

由于s是从前扫到后的,所以需要计算p[i]时一定已经计算好了p[1]....p[i-1]

假设现在扫描到了i+k这个位置,现在需要计算p[i+k]

 

定义maxlen是i+k位置前所有回文串中能延伸到的最右端的位置,即maxlen=p[i]+i;//p[i]+i表示最大的

 

分两种情况:

 

1.i+k这个位置不在前面的任何回文串中,即i+k>maxlen,则初始化p[i+k]=1;//本身是回文串

然后p[i+k]左右延伸,即while(s[i+k+p[i+k]] == s[i+k-p[i+k]])++p[i+k]

 

 

2.i+k这个位置被前面以位置i为中心的回文串包含,即maxlen>i+k

这样的话p[i+k]就不是从1开始

 

由于回文串的性质,可知i+k这个位置关于i与i-k对称,

所以p[i+k]分为以下3种情况得出

//黑色是i的回文串范围,蓝色是i-k的回文串范围,

技术分享

技术分享

技术分享

 

技术分享

 

技术分享
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
using namespace std;

const int N = 1e6+7;

char s[N];
int p[N];

int Manacher(char s[], int n)
{
    int Index = 0, maxlen = 0;
    for(int i=2; i<n; i++)
    {
        if(maxlen > i)
            p[i] = min(p[Index*2-i], maxlen-i);
        else
            p[i] = 1;
        while(s[i-p[i]]==s[i+p[i]])
            p[i]++;
        if(i+p[i]>maxlen)
        {
            maxlen = i+p[i];
            Index = i;
        }
    }
    int ans = 0;
    for(int i=2; i<n; i++)
        ans = max(ans, p[i]);
    return ans-1;
}

int main()
{
    while(scanf("%s", s)!=EOF)
    {
        memset(p, 0, sizeof(p));
        int len = strlen(s);
        for(int i=len; i>=0; i--)
        {
            s[i+i+2] = s[i];
            s[i+i+1] = #;
        }
        s[0] = $;
        int ans = Manacher(s, 2*len+2);
        printf("%d\n", ans);
    }
    return 0;
}
View Code

 

最长回文---hdu3068 (回文串 manacher 算法模板)

标签:

原文地址:http://www.cnblogs.com/zhengguiping--9876/p/4850254.html

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