hdu 3068 最长回文【manacher】(模板题)

<题目链接>

                                       最长回文

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算法
#include <iostream>
#include <cstring>
#include <string>
#include <map>
#include <queue>
#include <algorithm>
using namespace std;

char s[211000], c[111000];
int len[211000];      //Len[i]表示以字符s[i]为中心的最长回文字串的最右字符到s[i]的长度

//转换字符串
void init()
{
    int i, j;
    s[0] = '@';             //s[0]的初始化好像没什么用?
    for (i = 0; c[i] != 0; i++)
    {
        s[2 * i + 1] = '#';
        s[2 * i + 2] = c[i];
    }
    s[2 * i + 1] = '#';
    s[2 * i + 2] = 0;
}

int manacher()
{
    int id = 0, mx = 0, i;
    for (i = 1; s[i] != 0; i++)
    {                                       //  2*id-i,指的是i关于id 对称得到的坐标
         len[i] = mx>i ? min(len[2 * id - i], mx - i) : 1;    //因为前面已经算过了mx前的每个点的回文串,所以,如果这个i点在mx范围内,就将len[i]初始化为前面算过的数值

        while (s[i + len[i]] == s[i - len[i]])len[i]++;      
        if (i + len[i]>mx)
        {
            mx = i + len[i];      //mx为前i个回文子串的右端点所能到达的最大距离,即前面已经算过的最大回文区域
            id = i;               //记录下这个回文字串的中心位置
        }
    }

    int ans = 0;
    for (i = 1; s[i] != 0; i++)
    {
        if (len[i]>ans)ans = len[i];        //找到最大的len[i]
    }
    return ans - 1;          //回文串长度为len[i]-1,这个可以自己画图理解,因为s[]数组是在原串的基础上插入了 '#'
}

int main()
{
    while (~scanf("%s", c))
    {
        init();
        printf("%d\n", manacher());
    }
    return 0;
}

2018-08-04

猜你喜欢

转载自www.cnblogs.com/00isok/p/9419714.html
今日推荐