BISHI94 【模板】马拉车算法¶
中等通过率 47.9%python3样例通过牛客 AC
讲解章节:回文
一句话
求最长回文子串的长度,|S| <= 1e6。
解题思路¶
这题考什么¶
Manacher(马拉车算法,线性求出每个中心的回文半径,见 72-回文)。 朴素做法「枚举中心向两边扩」是 O(n^2),1e6 时是 1e12,必挂。 Manacher 靠「已经算出的最右回文区间 [l, r]」做镜像预测: 若当前中心 i < r,则 p[i] 至少是 min(r - i, p[mirror]), 从这个下界继续扩即可,整体均摊 O(n)。
奇偶统一的技巧:在每两个字符之间以及首尾插入分隔符 '#', 得到长度 2n+1 的新串 t。t 中每个位置的回文半径 p[i] 恰好等于原串中对应回文子串的长度(这是插入 '#' 的漂亮之处: 原长 L 的回文在 t 中半径就是 L,奇偶都不用分类讨论)。 所以答案就是 max(p)。
数据规模与复杂度¶
n <= 1e6 -> t 长 2e6+1,O(n)。
Python 的坑(本题必看)¶
- 构造 t 用 bytearray + 切片赋值: t = bytearray(b'#' * (2n+1)); t[1::2] = s 这比 '#'.join(s) 之类快得多,而且后续索引拿到的是 int,比较更快;
- 内层的 while 扩展循环要尽量精简:把 t、p 绑成局部变量, 边界判断合并成一次比较(这里在 t 两端各留一个哨兵位, 用不同的字符保证扩展一定会停下来,从而省掉两次下标越界检查);
- 一次性 read + 一次 write,不用 input()。
坑在哪¶
- 读入的一行字符串要用 split() 取第一个 token(顺带去掉换行 / 回车);
- p[i] 的初值必须是 min(r - i, p[2*c - i]), 忘了和 r - i 取 min 会越过已知区间导致错误;
- 更新最右区间时用 i + p[i] > r 判断,并同时更新中心 c。
参考实现¶
[:octicons-arrow-left-16: BISHI93](BISHI93.md) [BISHI95 :octicons-arrow-right-16:](BISHI95.md)