1. Manacher算法:解决最长回文子串问题的利器
在字符串处理领域,寻找最长回文子串是一个经典问题。回文串是指正读反读都相同的字符串,比如"abba"、"abcba"等。传统解决方案如中心扩展法虽然直观,但在处理长字符串时效率低下。Manacher算法应运而生,它通过巧妙的预处理和对称性利用,将时间复杂度从O(n²)降低到O(n),成为解决这一问题的黄金标准。
我第一次接触Manacher算法是在准备算法竞赛时。当时遇到一个需要处理百万级字符串的问题,使用传统方法总是超时。在尝试了Manacher算法后,不仅顺利通过了测试用例,执行时间也从秒级降到了毫秒级。这种性能提升让我深刻理解了算法优化的重要性。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 算法核心原理深度解析
2.1 传统方法的局限性
中心扩展法是最直观的解决方案:遍历每个可能的中心点(包括字符位置和字符间隙),向两边扩展直到不匹配为止。这种方法虽然简单,但存在明显缺陷:
cpp复制// 中心扩展法示例
int expand(const string& s, int l, int r) {
while (l >= 0 && r < s.size() && s[l] == s[r]) {
l--; r++;
}
return r - l - 1;
}
对于长度为n的字符串,最坏情况下(如全相同字符"aaaaa")需要进行O(n²)次比较。当n较大时(比如10^6),这种复杂度完全无法接受。
2.2 Manacher的突破性思路
Manacher算法的精妙之处在于两个关键创新:
- 统一奇偶处理:通过在字符间插入特殊符号(如'#'),将原字符串转换为始终具有奇数长度的新字符串。这样就不需要分别处理奇数和偶数长度的回文情况。
原始字符串:"abba"
转换后:"#a#b#b#a#"
- 利用对称性:维护一个"当前最右回文"的边界,对于新字符的位置,利用回文的对称性质避免重复计算。
2.3 核心概念详解
- p数组:记录以每个位置为中心的最长回文半径
- center:当前已知右边界最远的回文的中心
- right:该回文的最右边界
关键公式:
- 对称点计算:mirror = 2*center - i
- 初始半径:p[i] = min(right - i, p[mirror])
3. 完整实现与代码解析
3.1 预处理阶段
预处理是算法的第一步,也是理解整个算法的关键:
cpp复制string preprocess(const string& s) {
if (s.empty()) return "^$";
string t = "^";
for (char c : s) {
t += "#";
t += c;
}
t += "#$";
return t;
}
预处理后的字符串具有以下特点:
- 首尾添加特殊字符'^'和'$',避免边界检查
- 每个原始字符前后都插入'#',确保转换后字符串长度为奇数
- 预处理后的回文半径与原字符串回文长度的关系:length = p[i] - 1
3.2 核心算法实现
cpp复制string manacher(const string& s) {
string t = preprocess(s);
int n = t.size();
vector<int> p(n, 0);
int center = 0, right = 0;
for (int i = 1; i < n-1; ++i) {
int mirror = 2 * center - i;
if (i < right) {
p[i] = min(right - i, p[mirror]);
}
while (t[i + p[i] + 1] == t[i - p[i] - 1]) {
p[i]++;
}
if (i + p[i] > right) {
center = i;
right = i + p[i];
}
}
int max_len = 0, center_idx = 0;
for (int i = 1; i < n-1; ++i) {
if (p[i] > max_len) {
max_len = p[i];
center_idx = i;
}
}
int start = (center_idx - max_len) / 2;
return s.substr(start, max_len);
}
3.3 关键步骤解析
-
对称性利用:当i在已知回文右边界内时,可以利用对称点mirror的信息来初始化p[i],避免从零开始扩展。
-
中心扩展:在已有基础上继续向两边扩展,直到不匹配为止。这是算法中唯一的字符比较操作。
-
边界更新:如果当前回文扩展超过了已知右边界,则更新center和right。
-
结果转换:将预处理字符串中的回文信息转换回原始字符串的索
