manacher
马拉车算法是用来处理回文字符串的(其实可以用后缀数组但是后缀数组是nlogn的),其是一种非常的高效的简单算法
首先我们考虑一些暴力做法,考虑枚举位置i,然后对于任意一个i都向两边扩展,然后你就得到了一个n^2的假算。考虑有两个问题,一是你会发现对于偶数的串,会wa比如zqxxqz
其为1 1 1 1 1 1 然后就wa了,另一个问题是它是n^2的。
对于第一个问题我们在每个字符之间插入一个奇怪的字符,这样所有的串都会变成奇数串比如 %z%q%x%x%q%z%
对于第二个问题我们就要进行一些优化了,考虑如何利用上之前的求出的内容,我们考虑维护一个数组len[i]表示:对于一个以i为中心的回文串的右边的字符个数。
然后我们就会发现一个很显然的性质,以i为中心的原串的回文串长度=len[i]-1。(因为你往里面放了新的那个奇怪的字符)
然后我们就可以考虑如何求出len[i],考虑从左到右处理len[i]
考虑维护一个r一个mid,表示之前的所有len中右端点最远的r ,其对应的中心mid。
然后我们来进行分类讨论
若r>=i那么我们可以发现i被之前的回文串所覆盖了,那么它一定能得到其对称的那个串的长度但是要对于r-i取min(因为右边还没有被匹配)
若r<i那么我们可以发现他不可能用上之前的,所以他是1
然后我们开始往右扩展(就和暴力一样)
然后更新r和mid
浅浅的证明一下时间复杂度,我们会发现对于每一个位置他会由之前的扩展到或者有自己扩展,但不论被哪种方式扩展都只会被扩展一次,所以你就能够发现他是O(n)的
然后你就学会了这个简单的算法
然后发一下我写的很拉的代码
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> using namespace std; namespace lin { char s[11000100]; char t[22000100]; int len[22000100]; int love(int wjl) { scanf("%s",s+1); int n=strlen(s+1); int cnt=0; t[cnt]='&'; for(int i=1;i<=n;i++) { t[++cnt]='#'; t[++cnt]=s[i]; } t[++cnt]='#'; t[++cnt]='@'; int mid=0,r=0,ans=0; for(int i=1;i<cnt;i++) { len[i]=min(r-i,len[mid*2-i]); len[i]=max(len[i],1); while(t[i+len[i]]==t[i-len[i]]) len[i]++; if(i+len[i]>r) { r=i+len[i]; mid=i; } ans=max(len[i],ans); } printf("%d",ans-1); return wjl; } } int main() { return lin::love(0); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)