PAT甲级 1040 Longest Symmetric String(25) (Manacher)

题目

Given a string, you are supposed to output the length of the longest symmetric sub-string. For example, given Is PAT&TAP symmetric?, the longest symmetric sub-string is s PAT&TAP s, hence you must output 11.

输入

Each input file contains one test case which gives a non-empty string of length no more than 1000.

输出

For each test case, simply print the maximum length in a line.

样例输入 

Is PAT&TAP symmetric?

样例输出 

11

题意理解

给你一个字符串注意里面可能有空格 读入用getline 让你求出这个字符串的最大回文子串长度是多少

在做这题前我们先学习一下别的前导知识

回文串分为两种 分别是偶回文和奇回文 我们分别将其预处理成奇回文

只有奇回文判断回文时更加的方便 那么怎么统一预处理呢

1.预处理回文串

我们把这个回文串的每个字符左右两边都插入一个字符串中根本不存在的字符

举个例子 abba 长度为4 (偶数长度)

那么这个字符串就变成了 #a#b#b#a# 长度为9

再举个例子 aba 长度为3 (奇数长度)

那么这个字符串就变成了 #a#b#a# 长度为7

可以观察到 无论奇偶我们预处理结束之后都变成了奇回文串

2.最长回文子串的长度

我们之前以及预处理出来了这个新的回文串 那么我们获得最长回文子串呢

fabae 为例

预处理之后的回文串应该是 #f#a#b#a#e# 长度为11

这个时候 我们引入一个非常重要的对象 那就是 P数组

P数组存放的是以 i 这个点为中心点 当前这个位置的最长回文子串半径

i     0 1 2 3 4 5 6 7 8 9 10 11 
s[i]  @ # f # a # b # a # e  #
p[i]    1 2 1 2 1 4 1 2 1 2  1
 

为了方便我们操作 我们在头部放入一个肯定不等于字符串里面的字符也不等于我们的插入字符的一个字符 这样我们方便判断边界 这里选取了@ 中间插入的就是#

先分析一下回文半径与原字符串的关系 根据观察 

P[i]-1 就是我们以i为中心点扩散的回文串长度

最少是1因为一个字符的回文就是它本身

如何处理出P数组

设置两个变量 center radius

center 是所有回文子串中能延伸到最右端的位置的回文子串中心

radius 是延伸到最远的回文子串的右端的一个半径范围

当i等于6时 也就是 b这个字符 p[6]=4 也就是右端点到10 

那么右边界和其中心点的关系就是

  radius=i+P[i]

那么我们判断的是一个回文串

回文的性质就是相等 也就是说 以 center 为中心对称的左边 j 和 右边 i 的P数组值是一样的

j i 都已 center为中心对称

所以 如果 当前 radius >当前位置 

P数组的值就是 

Min(P[center*2-i],radius-i)

不然就是1

所以我们跑一遍Manacher最后就是结果了

代码 

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int max_ans=-1;
int p[N];
void manacher(string s){
    string ss="@#";
    for(int i=0;i<s.size();i++){
        ss+=s[i];
        ss+="#";
    }
    //中心点 半径范围
    int center=0,radius=0;
    for(int i=1;i<ss.size();i++){

        p[i]=radius>i ? min(p[center*2-i],radius-i):1 ;
        
        while(ss[i-p[i]]==ss[i+p[i]])p[i]++;
        
        if(radius<i+p[i]){
            center=i;
            radius=i+p[i];
        }
        max_ans=max(max_ans,p[i]-1);
    }
}
int main(){
    string s;
    getline(cin,s);
    manacher(s);
    cout<<max_ans<<endl;
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值