标签:子串 int manacher 复杂度 mid 对称中心 回文
喜闻乐见的zdc废话时间
之前听ckw讲过一次,但当时限于知识接受能力,并没有学懂事实上都没有听进去 然后决定就在子鼠年的最后一天学一下,结果发现这东西并不难,大概总结一下吧
manacher简介
用于求解最长回文子串问题,由于谐音,又名马拉车算法。
时间复杂度是线性的/se/se/se
具体实现
先考虑一个小问题
回文串有两类,一种是长度为奇数的,对称中心是字符;一种是长度为偶数的,对称中心是字符间隙。因为懒我们并不喜欢分类讨论,所以我们做一点处理把这两种情况归为一种
具体的,我们在字符之间和字符串头尾添加一个串中未出现过的字符(我喜欢用"#"),然后我们就会发现回文串都变成了奇数种(这里可以画图理解一下)
考虑如何暴力的求最长回文子串
暴力枚举所有端点然后暴力向两边扩展,时间复杂度是O(n^2)
那么来分析一下这个暴力算法的缺点
——有很多重叠的回文串被重复统计(大回文串套小回文串)
那么我们就从这个缺点入手
回文串有一个小性质:对于一个大回文串,设其对称中心为mid,其中的一个回文子区间关于mid的对称区间必为回文串。
那么我们设r当前回文子串最长向右扩展位置,mid为其对称中心,对于一个点i,设p[i]为以i为对称中心的最长回文子串长度。
考虑怎么求p[i]
结合之前所述性质,i的真实回文半径必定大于等于其关于mid的对称点的真实回文半径,而且这个性质是在大回文串中才会成立
所以形式化的
p[i]=min(p[mid*2-i],r-i+1);
ps:这里mid * 2 - i 就是i关于mid的对称点,具体求法大概是这样,设对称点为 j ,显然,mid为 i,j 中点,根据中点公式:mid = ( i + j ) / 2。移项可得,j = (mid<<1) - i。
最后因为是大于等于号所以我们再去尝试扩展,然后更新r和mid
最终答案就为 max{ p [ i ] }-1 (画图理解一下吧,注意这里的串我们已经加字符了哦)
先贴一下模板代码(缺省源自带快读请忽视)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define _rep(i,x,y) for(int i=x;i>=y;i--)
#define int long long
#define N 22000010
const int inf=1e18;
inline int read()
{
int num=0,fu=1; char c=getchar();
while(c!='-'&&(c>'9'||c<'0')) c=getchar();
if(c=='-') fu=-1,c=getchar();
while(c>='0'&&c<='9') num=(num<<3)+(num<<1)+(c^48),c=getchar();
return fu*num;
}
int tmp,n,ans,p[N];
char s[N],a[N];
signed main()
{
scanf("%s",a+1);
tmp=strlen(a+1);
s[0]='#'; s[1]='#';
rep(i,1,tmp) s[i*2]=a[i],s[i*2+1]='#';
n=tmp*2+1;
int mid=0,mxr=0;
rep(i,1,n)
{
if(i<=mxr) p[i]=min(mxr-i+1,p[(mid<<1)-i]);
while(s[i-p[i]]==s[i+p[i]]) p[i]++;
if(i+p[i]-1>mxr) mxr=i+p[i]-1,mid=i;
}
rep(i,1,n) ans=max(ans,p[i]-1);
printf("%lld\n",ans);
return 0;
}
时间复杂度分析
在上述过程中,r(代码中为mxr)只会向右移动,最终也只会移动到串尾(结合双指针的时间复杂度分析),所以复杂度是线性的。
标签:子串,int,manacher,复杂度,mid,对称中心,回文 来源: https://www.cnblogs.com/Ing1024/p/14493894.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。