【模板】最长回文子串(马拉车)

题目:求一个给定字符串的最长回文子串

[2022重新编辑]
核心思路:根据回文串的对称性剪枝

  1. 关于字符串长度奇偶性问题:
    考虑到,如果回文串长度是奇数是偶数 所需要的操作不同,处理起来比较麻烦。
    所以我们对原串做点手脚,即把每两个字符之间和头尾都加一个’#’
    最后算出回文串长度后再将加上的’#'减去即可
  2. 数组定义:
    len[i]表示以 i 为中心的回文串的最长长度的一半,即 子串半径
    我们随时记录与更新p与p0,p表示已判断出过的所有回文串的最右端点位置,p0表示这个以p为最右端点的回文子串的中心点。
  3. 状态转移:
    当我们要求len[i]时,有以下三种情况
    情况1:i 在 p 的右面,没什么可优化的,只能以i为中心向两边扩散距离,计算最长长度
    ( 记 j 为 i 关于 po 的对称,即 j=po-(i-po) )
    情况2:i 在 p左面, 且 以 po为中心的回文串 完全包含了以 j 为中心的回文子串,即 po-len[po]<=j-len[j] 这时,根据回文串对称性,状态转移,len[i]=len[j]
    情况3:i 在p左面,但 以j为中心的回文子串的左端点超过了po回文串的左端点,即 po-len[po]>j-len[j],根据对称性,未超出的部分可以免去判断,只需判断超出部分。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#if 0
Writer: Goes && G.S.M.
Just a game
Enjoy it
#endif
inline char read(){
	char ch=getchar();
	while(ch<'a'||ch>'z') ch=getchar();
	return ch;
}
char s[10000005],ch;
int len[10000005],po,p,ans;
int main()
{
	//读入与预处理
	int l=0;ch=read();
	s[++l]='#';s[0]='$';
	while(ch>='a'&&ch<='z')
		s[++l]=ch,s[++l]='#',ch=getchar();
	s[++l]='\0';
	//状态更新
	for(int i=0;i<l;i++){
		if(p>i) len[i]=min(len[po*2-i],p-i);//完全包含和不完全包含的两种情况
		else len[i]=1;//i在右面
		while(s[i+len[i]]==s[i-len[i]]) len[i]++;//不包含部分,暴力判断
		if(i+len[i]>p) po=i,p=len[i]+i;//更新p与po
	}
	for(int i=0;i<l;i++)
		ans=max(ans,len[i]);
	cout<<ans-1<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GoesM

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值