问题简介
题目描述
给你一个字符串 s,找到 s 中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
示例说明
✅ 示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
✅ 示例 2:
输入:s = "cbbd"
输出:"bb"
✅ 示例 3:
输入:s = "a"
输出:"a"
✅ 示例 4:
输入:s = "ac"
输出:"a" 或 "c"
解题思路
📌 回文串具有对称性。我们可以从中心向两边扩展(中心扩散法),也可以使用动态规划记录子串是否为回文。
✅ 方法一:中心扩散法(推荐)
- 枚举每一个可能的回文中心(包括奇数长度和偶数长度)。
- 对于每个中心,向左右扩展,直到字符不匹配。
- 记录过程中最长的回文子串。
💡 关键点:
- 奇数长度回文:中心是一个字符(如
"aba",中心是'b')。 - 偶数长度回文:中心在两个字符之间(如
"abba",中心在两个'b'之间)。
时间复杂度较低,代码简洁。
✅ 方法二:动态规划
- 定义
dp[i][j]表示子串s[i..j]是否为回文。 - 状态转移:
- 如果
s[i] == s[j]且(j - i < 2 || dp[i+1][j-1]),则dp[i][j] = true。
- 如果
- 遍历所有子串,更新最长回文。
空间复杂度较高,但逻辑清晰。
❌ 方法三:暴力枚举(不推荐)
- 枚举所有子串,判断是否为回文。
- 时间复杂度 O(n³),会超时。
代码实现
java:Java
class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() < 1) return "";
int start = 0, end = 0;
for (int i = 0; i < s.length(); i++) {
int len1 = expandAroundCenter(s, i, i); // 奇数长度
int len2 = expandAroundCenter(s, i, i + 1); // 偶数长度
int len = Math.max(len1, len2);
if (len > end - start) {
start = i - (len - 1) / 2;
end = i + len / 2;
}
}
return s.substring(start, end + 1);
}
private int expandAroundCenter(String s, int left, int right) {
while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
left--;
right++;
}
return right - left - 1;
}
}
go:Go
func longestPalindrome(s string) string {
if len(s) == 0 {
return ""
}
start, end := 0, 0
for i := 0; i < len(s); i++ {
len1 := expandAroundCenter(s, i, i)
len2 := expandAroundCenter(s, i, i+1)
length := max(len1, len2)
if length > end-start {
start = i - (length-1)/2
end = i + length/2
}
}
return s[start : end+1]
}
func expandAroundCenter(s string, left, right int) int {
for left >= 0 && right < len(s) && s[left] == s[right] {
left--
right++
}
return right - left - 1
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
💡 上述代码均采用中心扩散法,简洁高效。
示例演示
以 s = "babad" 为例:
| 中心位置 | 类型 | 扩展过程 | 回文长度 | 当前最长 |
|---|---|---|---|---|
| i=0 | 奇 | "b" |
1 | "b" |
| i=0 | 偶 | "ba" ❌ |
0 | "b" |
| i=1 | 奇 | "a" → "bab" |
3 | "bab" |
| i=1 | 偶 | "ab" ❌ |
0 | "bab" |
| i=2 | 奇 | "b" → "aba" |
3 | "bab"(或 "aba") |
| ... | ... | ... | ... | ... |
最终返回 "bab" 或 "aba",均合法。
答案有效性证明
✅ 正确性:
- 所有可能的回文中心都被枚举(共
2n - 1个:n个单字符 +n-1个双字符间隙)。 - 每次扩展都保证了回文性质(左右字符相等才继续)。
- 记录了最大长度对应的起止位置,确保结果正确。
✅ 边界处理:
- 空字符串、单字符、无回文(如
"abc")均能正确返回。
复杂度分析
| 方法 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 中心扩散法 | O(n²) | O(1) |
| 动态规划 | O(n²) | O(n²) |
| 暴力枚举 | O(n³) | O(1) |
📌 中心扩散法最优:常数空间,且实际运行快(内层循环通常提前终止)。
问题总结
✅ 核心思想:利用回文的对称性,从中心向外扩展。
✅ 技巧:
- 同时处理奇偶长度回文。
- 通过
start和end记录位置,避免频繁字符串拼接。
✅ 适用场景:适用于所有需要查找回文子串的问题(如回文子串个数、最长回文子序列等变种)。
💡 延伸思考:
- 若需找所有回文子串,可修改中心扩散法收集结果。
- 更优解法(如 Manacher 算法)可在 O(n) 时间解决,但实现复杂,面试中较少要求。
github地址: https://github.com/swf2020/LeetCode-Hot100-Solutions