题目:最长回文子串
给定一个字符串 s,求 s 中最长的回文子串。
解题思路
本方法采用 中心扩展法(Expand Around Center),以每个字符(或字符对)为中心向外扩展,找出最长回文子串。
1. 核心思想
任何回文字符串,都有一个 中心对称结构,可以分为:
1. 奇数长度的回文(如 "aba",中心是 'b')
2. 偶数长度的回文(如 "abba",中心是 bb)
我们可以:
• 以 每个字符 作为 奇数长度回文 的中心
• 以 相邻的两个字符 作为 偶数长度回文 的中心
然后 向外扩展,直到不再是回文。
2. 代码解析
class Solution {
public:
string longestPalindrome(string s) {
if (s.empty()) return ""; // 处理空字符串情况
int start = 0, maxLen = 0; // 记录最长回文子串的起始索引和长度
for (int i = 0; i < s.size(); i++) {
// 以 s[i] 为中心扩展(奇数长度)
int len1 = expandFromCenter(s, i, i);
// 以 s[i] 和 s[i+1] 为中心扩展(偶数长度)
int len2 = expandFromCenter(s, i, i + 1);
int len = max(len1, len2); // 取最大回文长度
if (len > maxLen) { // 如果找到更长的回文,更新起点和长度
maxLen = len;
start = i - (len - 1) / 2; // 计算回文起点
}
}
return s.substr(start, maxLen); // 返回最长回文子串
}
// 辅助函数:从中心点 (left, right) 开始向外扩展,返回回文长度
int expandFromCenter(const string& s, int left, int right) {
while (left >= 0 && right < s.size() && s[left] == s[right]) {
left--; // 左指针左移
right++; // 右指针右移
}
return right - left - 1; // 计算回文长度
}
};
3. 具体运行步骤
示例 1
输入:
s = "babad"
步骤:
i | expandFromCenter(s, i, i) | expandFromCenter(s, i, i+1) | 取最大值 | 更新 start | maxLen |
---|---|---|---|---|---|
0 | "b" → 1 | "ba" → 0 | 1 | 0 | 1 |
1 | "bab" → 3 | "ba" → 0 | 3 | 0 | 3 |
2 | "aba" → 3 | "ad" → 0 | 3 | 1 | 3 |
3 | "d" → 1 | "da" → 0 | 1 | - | - |
4 | "a" → 1 | "a" → 0 | 1 | - | - |
输出: "aba" 或 "bab"
示例 2
输入:
s = "cbbd"
步骤:
i | expandFromCenter(s, i, i) | expandFromCenter(s, i, i+1) | 取最大值 | 更新 start | maxLen |
---|---|---|---|---|---|
0 | "c" → 1 | "cb" → 0 | 1 | 0 | 1 |
1 | "b" → 1 | "bb" → 2 | 2 | 1 | 2 |
2 | "b" → 1 | "bd" → 0 | 1 | - | - |
3 | "d" → 1 | "d" → 0 | 1 | - | - |
输出: "bb"
4. 复杂度分析
• 时间复杂度: O(n²)
• 对于每个 i,调用 expandFromCenter 可能遍历整个字符串,因此最坏情况下 O(n²)。
• 空间复杂度: O(1)
• 只使用了常数级额外变量,不需要 dp 数组。
5. 总结
✅ 优点:
• 比 DP 方法更快,且省去 O(n²) 额外空间
• 容易实现,逻辑清晰
• 适用于一般字符串情况
✅ 缺点:
• 最坏情况下仍是 O(n²)
• 无法处理特殊优化情况,如 Manacher 算法可优化至 O(n)