题目
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 iss PAT&TAP s
, hence you must output11
.
输入
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
为了方便我们操作 我们在头部放入一个肯定不等于字符串里面的字符也不等于我们的插入字符的一个字符 这样我们方便判断边界 这里选取了@ 中间插入的就是#
先分析一下回文半径与原字符串的关系 根据观察
就是我们以i为中心点扩散的回文串长度
最少是1因为一个字符的回文就是它本身
如何处理出P数组
设置两个变量 center radius
center 是所有回文子串中能延伸到最右端的位置的回文子串中心
radius 是延伸到最远的回文子串的右端的一个半径范围
当i等于6时 也就是 b这个字符 p[6]=4 也就是右端点到10
那么右边界和其中心点的关系就是
那么我们判断的是一个回文串
回文的性质就是相等 也就是说 以 center 为中心对称的左边 j 和 右边 i 的P数组值是一样的
j i 都已 center为中心对称
所以 如果 当前 radius >当前位置
P数组的值就是
不然就是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;
}