manacher 算法
manacher 算法
求有关回文的字符串算法。
定义 表示字符串下标 到 形成的子串。
流程
- 将原字符串首、尾、中间分别插入奇怪字符(如
#
,目的是计算中心点在两个字符之间的回文串),再在最前端插入另一奇怪字符串(如@
,目的是防止数组越界),eg.abcb
变为@#a#b#c#b#
。 - 对每个位置记录 表示在当前字符串以 为回文中心的最大回文串为 。
- 考虑从前往后做,边做边记录两个值,分别为 分别表示当前所有回文串中,右端点最大的回文串对应的回文中心以及右端点。显然这个可以边做边维护。
- 考虑如何求 ,如果说 ,那么 关于 对称的 的信息我们是可以用到的(若 超出 ,则超出的那个部分不可取)。具体来说,如果 ,,否则 。
- 不断扩大 ,直到求出 。
时间复杂度证明
- 若 ,则 随着 增大而增大。
- 若 ,则 不会再继续扩展。
- 若 ,则 随着 增大而增大。
故, 均会随着 增大而增大,又考虑到 最多增大 次,故时间复杂度为 。
回文串大小
根据 的定义,其实对应到原串上,以 为对称中心的最大的回文串长度为 (可以分情况讨论,这里不展开)。
#include <bits/stdc++.h>
const int N = 1.1e7 + 10;
int len, lenr;
char s[N], r[N * 2];
int p[N * 2], ans;
inline void manacher()
{
int id = 0, maxright = 0;
for (int i = 1; i <= lenr; ++ i)
{
if (maxright > i)
p[i] = std::min(maxright - i + 1, p[id * 2 - i]);
else p[i] = 0;
while (r[i + p[i]] == r[i - p[i]])
p[i] ++;
if (i + p[i] - 1 > maxright)
{
id = i;
maxright = i + p[i] - 1;
}
ans = std::max(ans, (p[i] - 1));
}
}
int main()
{
scanf("%s", s + 1);
len = strlen(s + 1);
r[0] = '@';
for (int i = 1; i <= len; ++ i)
r[i * 2 - 1] = '#', r[i * 2] = s[i];
r[len * 2 + 1] = '#';
lenr = len * 2 + 1;
manacher();
printf("%d\n", ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧