LeetCode 5. 最长回文子串——中心扩展法彻底讲透
一、题目描述
给定一个字符串 s,找到其中最长的回文子串,并返回这个子串。
示例:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
输入:s = "cbbd"
输出:"bb"
二、什么是回文串?
回文串(Palindrome):
正着读和反着读完全一样的字符串。
例如:
"a"
"aa"
"aba"
"abba"
"racecar"
都属于回文串。
而:
"ab"
"abc"
"abca"
不是回文串。
三、回文的核心性质:左右对称
所有回文串一定存在一个「对称中心」。
例如:
奇数长度回文
aba
a ← b → a
中心是:
b
偶数长度回文
abba
ab ← → ba
中心是:
两个字符之间的缝隙
因此:
只要找到所有可能的对称中心,然后不断向两边扩散,就能找到所有回文串。
这就是中心扩展法。
四、整体思路
对于字符串中的每一个位置 i:
我们都尝试两种情况:
情况1:奇数回文
expand(i, i)
例如:
aba
^
情况2:偶数回文
expand(i, i + 1)
例如:
abba
^^
每次扩散结束后:
记录当前回文的长度。
如果比之前最长的回文还长:
就更新答案。
五、扩散函数怎么写?
定义函数:
expand(left, right)
表示:
从 left 和 right 开始向两边扩散。
扩散条件
三个条件必须同时满足:
left >= 0
right < len(s)
s[left] == s[right]
满足条件:
left -= 1
right += 1
继续扩散。
为什么最后要回退?
例如:
aba
扩散过程:
left=1 right=1
↓
left=0 right=2
↓
left=-1 right=3
退出循环时:
left=-1
right=3
已经越界了。
真正有效的边界应该是:
0 ~ 2
因此返回:
left + 1
right - 1
六、完整代码
class Solution:
def longestPalindrome(self, s: str) -> str:
# 长度小于2直接返回
if len(s) < 2:
return s
start = 0
end = 0
def expand(left, right):
while (
left >= 0
and right < len(s)
and s[left] == s[right]
):
left -= 1
right += 1
return left + 1, right - 1
for i in range(len(s)):
# 奇数长度回文
l1, r1 = expand(i, i)
# 偶数长度回文
l2, r2 = expand(i, i + 1)
# 更新最长奇数回文
if r1 - l1 > end - start:
start = l1
end = r1
# 更新最长偶数回文
if r2 - l2 > end - start:
start = l2
end = r2
return s[start:end + 1]
七、拿示例跑一遍
字符串:
s = "babad"
i = 0
奇数:
b
长度:
1
偶数:
无
最长:
b
i = 1
奇数:
bab
长度:
3
更新答案:
bab
偶数:
无
i = 2
奇数:
aba
长度:
3
和当前最长相同。
保持:
bab
最终返回:
bab
八、为什么 i + 1 不会越界?
假设:
s = "abc"
最后一次:
i = 2
expand(2, 3)
进入函数:
right < len(s)
即:
3 < 3
不成立。
直接退出。
不会报错。
九、复杂度分析
时间复杂度
O(n²)
共有:
2n 个中心
每个中心最多扩散:
O(n)
因此:
O(n²)
空间复杂度
O(1)
只使用有限几个变量。
十、高频易错点
1、只处理奇数回文
错误:
expand(i, i)
遗漏:
expand(i, i + 1)
会导致:
"cbbd"
输出错误。
2、扩散使用 if
错误:
if s[left] == s[right]:
只能扩一层。
必须使用:
while
持续扩散。
3、忘记回退边界
错误:
return left, right
应该:
return left + 1, right - 1
4、长度公式少写 +1
错误:
right - left
正确:
right - left + 1
5、字符串切片忘记 +1
错误:
s[start:end]
正确:
s[start:end + 1]
因为 Python 切片:
左闭右开
十一、一句话总结
最长回文子串的核心思想:
枚举每一个可能的回文中心,从中心向两边不断扩散,记录最长回文的左右边界。
记忆口诀:
一个字符找奇数,
两个字符找偶数;
左右不断往外扩,
记录最长回文串。
949

被折叠的 条评论
为什么被折叠?



