hiho第一周——最长回文子串

hiho第一周——最长回文子串

题目链接:http://hihocoder.com/contest/hiho1/problem/1
资料来源于网络:http://www.felix021.com/blog/read.php?2040

关键点

Manacher算法的关键点就在这里了:如果max_right> i,那么P[i] >= MIN(P[2 * ind - i], max_right- i)

上图方便理解:

当 mx - i > P[j] 的时候,以S[j]为中心的回文子串包含在以S[id]为中心的回文子串中,由于 i 和 j 对称,以S[i]为中心的回文子串必然包含在以S[id]为中心的回文子串中,所以必有 P[i] = P[j],见下图。
这里写图片描述

当 P[j] >= mx - i 的时候,以S[j]为中心的回文子串不一定完全包含于以S[id]为中心的回文子串中,但是基于对称性可知,下图中两个绿框所包围的部分是相同的,也就是说以S[i]为中心的回文子串,其向右至少会扩张到mx的位置,也就是说 P[i] >= mx - i。至于mx之后的部分是否对称,就只能老老实实去匹配了。
这里写图片描述

p.s.数组 P[i] 来记录以字符S[i]为中心的最长回文子串向左/右扩张的长度(包括S[i])

可执行代码

#include <iostream>
#include <string>
#include <fstream>
#include <cmath>
#include <vector>
using namespace std;

int longest_panlin(string s);

int main()
{
    fstream cin("input.txt");
    int N;
    cin>>N;
    while(N>0)
    {
        string s;
        cin>>s;
        int result;
        result=longest_panlin(s);
        cout<<result<<endl;
        N--;
    }
    return 0;
}


int longest_panlin(string s)
{
    //预处理,因为manacher算法对于奇数个字符的字符串,代码可以大大简化(但是这加大了空间复杂度)
    string str="#";
    for(int i=0;i<s.size();i++){str+=s[i];str+='#';}
    //记录最长回文子串的长度。比如以c为中心的#a#c#a#,它的result为4,最终函数应该返回3
    int result=0;
    //右端最右的回文子串,它的中心位置
    int ind=0;
    //右端最右的回文子串,它的右端位置
    int max_right=0;
    int n=str.size();
    //动态数组,记录以下标为中心位置,它的最长回文字串的右边长度(包括中心点)
    int *p=new int[n];
    p[0]=1;

    for(int i=1;i<n;i++)
    {
        //该算法的核心思想,具体请看图
        if(max_right>i)
            p[i]=min(p[2*ind-i],max_right-i);
        else
            p[i]=1;
        //在不越左边界,不越右边界的情况下,获取该中心的回文子串最大的长度
        for(;i>=p[i]&&i+p[i]<n&&str[i+p[i]]==str[i-p[i]];)
            p[i]++;
        //记录结果
        if(p[i]>result)result=p[i];
        //不断获得右端最右的回文子串(这是为什么呢?是跟时间复杂度有关吗?)
        if(p[i]+i>max_right)
        {
            max_right=p[i]+i;
            ind=i;
        }
    }
    delete p;
    return result-1;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值