在字符串处理中,最长回文子串是一个经典问题。暴力解法的时间复杂度高达 O(n³),即使优化后也仅能达到 O(n²)。而Manacher算法是一种线性时间复杂度 O(n) 的高效算法,专门用于解决此类问题。
本文将用通俗易懂的方式,手把手教你理解并用 C++ 实现 Manacher 算法,即使你是编程小白也能轻松掌握!
回文是指正着读和反着读都一样的字符串,例如:"aba"、"abba"、"racecar" 等。
传统的中心扩展法对每个字符都尝试向两边扩展,最坏情况下仍需 O(n²) 时间。而 Manacher算法 利用回文的对称性,避免重复计算,从而将时间复杂度降至 O(n)。
Manacher 算法的关键在于两个技巧:
"abba" → "#a#b#b#a#"。
假设原字符串为 s,我们构造新字符串 t,并在其上定义数组 P,其中 P[i] 表示以 t[i] 为中心的最长回文半径(包含中心)。
算法流程如下:
s 的每个字符间插入特殊字符(如 '#'),首尾也加哨兵(如 '^' 和 '$' 防越界)。C = 0(当前回文中心),R = 0(当前最右边界)。t 中每个位置 i:i < R,则利用对称性:P[i] = min(R - i, P[2*C - i])。i 为中心向外扩展,更新 P[i]。R,更新 C = i 和 R = i + P[i]。max(P) - 1。下面是一个完整的、可运行的 C++ 实现:
#include <iostream>#include <string>#include <vector>#include <algorithm>using namespace std;string preprocess(const string& s) { // 在字符串前后加上哨兵,中间插入 '#' string t = "^#"; for (char c : s) { t += c; t += '#'; } t += "$"; return t;}string longestPalindrome(const string& s) { if (s.empty()) return ""; string t = preprocess(s); int n = t.length(); vector<int> P(n, 0); int C = 0, R = 0; // 当前中心和最右边界 for (int i = 1; i < n - 1; i++) { // 利用对称性 int mirror = 2 * C - i; if (i < R) { P[i] = min(R - i, P[mirror]); } // 尝试扩展 while (t[i + (1 + P[i])] == t[i - (1 + P[i])]) { P[i]++; } // 更新中心和右边界 if (i + P[i] > R) { C = i; R = i + P[i]; } } // 找到最大回文半径及其位置 int maxLen = 0, centerIndex = 0; for (int i = 1; i < n - 1; i++) { if (P[i] > maxLen) { maxLen = P[i]; centerIndex = i; } } // 转换回原字符串的起始位置 int start = (centerIndex - maxLen) / 2; return s.substr(start, maxLen);}int main() { string s = "babad"; cout << "最长回文子串: " << longestPalindrome(s) << endl; return 0;}
'#',将所有回文统一为奇数长度,简化逻辑。i 在 R 内时,其对称点 mirror 的回文信息可直接复用,但不能超过 R - i。Manacher算法 是解决 最长回文子串 问题的最优解之一,特别适合在竞赛或高性能场景中使用。通过本文的讲解和 C++ 代码示例,相信你已经掌握了这一强大工具。
记住,理解算法的核心思想比死记代码更重要。多动手实践,尝试修改输入字符串,观察 P 数组的变化,你会对 字符串算法 有更深的体会!
希望这篇教程对你有帮助!如果你喜欢,请分享给更多学习 C++回文字符串 处理的朋友吧!
本文由主机测评网于2025-12-27发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://vpshk.cn/20251213094.html