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

HDU 3068 最长回文(Manacher算法模板)

时间:2015-10-12 10:27:14      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:

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
 
详解:O(n)回文子串(Manacher)算法 - as_ - 博客园 http://www.cnblogs.com/biyeymyhjob/archive/2012/10/04/2711527.html
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

const int N=1e6+10;

char S[N], s[N];
int r[N], k; ///r数组中保存以i为中心的回文串的半径

int Manacher() ///求出字符串中最大回文串的长度
{
    int i, mx, id = 0, Max = 0; ///mx是以id为中心的回文串的边界

    for (i = 2; i < k; i++)
    {
        r[i] = 1;

        mx = r[id]+id; 

        if (mx > i) r[i] = min(r[2*id-i], mx-i); ///如果以id为中心的回文串边界大于i,则有两种情况,一种是以i为中心的回文串包含在id中,那么以i为中心的半径就是(2*id-i)的半径,因为该点是i关于id对称的点
                                                 ///第二种是没有完全包含在id中,那么我们只能确定mx-i是最小的半径,最终取两者最小值(这是一种线性关系)
        while (s[i-r[i]] == s[i+r[i]]) r[i]++; ///再求完半径的最小值之后剩下的部分还是要判断是否属于这个半径的

        if (mx < r[i]+i) id = i; ///因为要找的是最大值,所以更新

        Max = max(Max, r[i]-1);
    }

    return Max;
}

int main()
{
    int i, ans;

    while (scanf("%s", S) != EOF)
    {
        memset(r, 0, sizeof(r));
        k = 2;

        s[0] = $; s[1] = #; ///为了避免处理边界,s[0]置为特殊符号
        for (i = 0; S[i] != \0; i++)
        {
            s[k++] = S[i];
            s[k++] = #;
        } ///将字符串长度变为奇数

        ans = Manacher();

        printf("%d\n", ans);
    }

    return 0;
}
 

HDU 3068 最长回文(Manacher算法模板)

标签:

原文地址:http://www.cnblogs.com/syhandll/p/4870764.html

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