manacher 算法

manacher 算法

题目大意:求最长回文子串的长度(题目

分析:

  1. 设字符串为 S S S,首先我们要寻找它的对称中心,但发现对称中心可能在一个字符上,也可能在两个字符中间如图因为在两个字符中间的我们不好访问,于是我们可以在中间插入一些无关的字符,让字符来代替中间的空隙在这里插入图片描述
  2. 我们记录一个数组 P P P P i P_i Pi表示以 S i S_i Si为中心的回文数列的最大半径在这里插入图片描述如图, P 7 = 6 P_7=6 P7=6,在记录 m i d , r mid,r mid,r,表示当前已知的 P i P_i Pi中, P m i d + r P_{mid}+r Pmid+r是最大的,即右区间离 S S . l e n g t h ( ) S_{S.length()} SS.length()最近
  3. 于是对于一个未知的 P i P_i Pi如果 i ⩽ P m i d + r i \leqslant P_{mid}+r iPmid+r那么就可以根据回文数的对称性,确定在 m i d − r ⩽ i ⩽ m i d + r mid-r \leqslant i \leqslant {mid}+r midrimid+r这段区间里, P i = m i n ( P 关 于 m i d 对 称 的 点 , m i d + r − i ) P_i=min(P_{关于mid对称的点},mid+r-i) Pi=min(Pmid,mid+ri),易得对称点为 2 ∗ m i d − i 2*mid-i 2midi,于是 P i = m i n ( P 2 ∗ m i d − i , m i d + r − i ) P_i=min(P_{2*mid-i},mid+r-i) Pi=min(P2midi,mid+ri)
  4. 但是我们不知道 m i d + r mid+r mid+r后面是否还有相同的 P x , P y P_x,P_y Px,Py,所以要暴力枚举,最后更新 m i d , r mid,r mid,r
  5. 于是最大值就是 P m a x P_{max} Pmax

代码实现:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;

void read(int &sum)
{
	sum=0;char last='w',ch=getchar();
	while (ch<'0' || ch>'9') last=ch,ch=getchar();
	while (ch>='0' && ch<='9') sum=sum*10+ch-'0',ch=getchar();
	if (last=='-') sum=-sum;
}
char s[11000002*2],g[11000002*2];
int p[11000002*2];
int len;
int main()
{
//	freopen("M.in","r",stdin);
//	freopen("M.out","w",stdout);
	s[++len]='|';
	char ch=getchar();
	while (ch!=EOF)
	{
		s[++len]=ch;
		s[++len]='|';
		ch=getchar();
	}
	int mmax=0;
//	for (int i=1;i<=len;i++) printf("%c",s[i]);
	for (int i=1,r=0,mid=0;i<=len;i++)
	{
		if (i<=mid+r) p[i]=min(p[2*mid-i],mid+r-i+1);
		while (i-p[i]>=1 && i+p[i]<=len && s[i-p[i]]==s[i+p[i]]) p[i]++;
		if (s[i-p[i]]!=s[i+p[i]] || i-p[i]<1 || i+p[i]>len) p[i]--;
		if (i+p[i]>r) r=p[i],mid=i;
		mmax=max(mmax,p[i]);
	}
//	printf("\n");
	printf("%d",mmax);
//	fclose(stdin);fclose(stdout);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值