本文实现 Manacher 算法案例,用于求解字符串中的最长回文子串。
问题描述
给定一个字符串 s
,如何高效地找到其中的最长回文子串?
算法思想
Manacher 算法是一种基于中心扩展法和动态规划的算法,其核心思想是通过维护一个回文半径数组 p
,避免重复计算。具体步骤如下:
- 将字符串
s
转换为添加分隔符的形式(如#a#b#a#
),以统一处理奇偶长度的回文子串。 - 维护一个回文半径数组
p
,其中p[i]
表示以i
为中心的最长回文半径。 - 利用已知的回文信息,快速扩展当前中心的回文半径。
- 最终,
max(p) - 1
即为最长回文子串的长度。
C++代码实现
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// Manacher 算法实现
string longestPalindrome(string s) {
// 预处理字符串
string t = "#";
for (char ch : s) {
t += ch;
t += "#";
}
int n = t.size();
vector<int> p(n, 0); // 回文半径数组
int center = 0, right = 0; // 当前回文中心和右边界
int maxLen = 0, maxCenter = 0; // 最长回文子串的长度和中心
for (int i = 0; i < n; i++) {
// 利用对称性快速初始化 p[i]
if (i < right) {
p[i] = min(right - i, p[2 * center - i]);
}
// 尝试扩展回文半径
while (i - p[i] - 1 >= 0 && i + p[i] + 1 < n && t[i - p[i] - 1] == t[i + p[i] + 1]) {
p[i]++;
}
// 更新回文中心和右边界
if (i + p[i] > right) {
center = i;
right = i + p[i];
}
// 更新最长回文子串信息
if (p[i] > maxLen) {
maxLen = p[i];
maxCenter = i;
}
}
// 提取最长回文子串
int start = (maxCenter - maxLen) / 2;
return s.substr(start, maxLen);
}
int main() {
string s = "babad";
string result = longestPalindrome(s);
cout << "最长回文子串是: " << result << endl;
return 0;
}
关键解析
- 时间复杂度:
O(n)
,其中n
是字符串的长度。 - 空间复杂度:
O(n)
,用于存储回文半径数组。 - 适用场景:
- 查找字符串中的最长回文子串。
- 需要高效处理大规模字符串。
输出示例
最长回文子串是: bab
总结
Manacher 算法是一种高效的最长回文子串查找算法,通过利用回文对称性和动态规划的思想,避免了重复计算。