| 排名 | 题号 | 题目名称 | 难度 | 频度 | 链接 |
|---|---|---|---|---|---|
| 2 | 5 | 最长回文子串 | 中等 | 318 | LeetCode |
给你一个字符串 s,找到 s 中最长的 回文 子串。
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"
输出:"bb"
提示:
1 <= s.length <= 1000s仅由数字和英文字母组成
python
def longestPalindrome(s: str) -> str:
"""
找出字符串中最长的回文子串
算法思路:中心扩散法
- 回文串是对称的,从中心向两边扩散
- 每个字符(或字符间隙)都可以作为中心
- 遍历所有可能的中心,找出最长的回文
时间复杂度:O(n²),n个中心,每个中心最多扩散n次
空间复杂度:O(1),只需常数级变量
"""
if len(s) < 2:
return s
# 记录最长回文的起始位置和长度
start = 0
max_length = 0
for i in range(len(s)):
# 情况1:以单个字符为中心(奇数长度回文)
# 例如 "aba",中心是 'b'
len1 = expand_around_center(s, i, i)
# 情况2:以两个字符之间的间隙为中心(偶数长度回文)
# 例如 "abba",中心在两个 'b' 之间
len2 = expand_around_center(s, i, i + 1)
# 取两种情况中的较大值
current_length = max(len1, len2)
# 如果找到更长的回文,更新记录
if current_length > max_length:
max_length = current_length
# 计算回文串的起始位置
# 如果是奇数长度:i - len1//2
# 如果是偶数长度:i - len2//2 + 1
start = i - (current_length - 1) // 2
# 返回最长回文子串
return s[start:start + max_length]
def expand_around_center(s: str, left: int, right: int) -> int:
"""
从中心向两边扩散,寻找回文
参数:
left: 左指针起始位置
right: 右指针起始位置
返回:
回文串的长度
"""
# 当左右指针不越界,且字符相等时,继续扩散
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1 # 左指针向左移动
right += 1 # 右指针向右移动
# 退出循环时,s[left] != s[right] 或越界
# 回文串范围是 (left+1, right-1),长度 = right - left - 1
return right - left - 1
# 测试用例
if __name__ == "__main__":
# 测试1: "babad" → "bab" 或 "aba",长度为3
test1 = "babad"
print(f"输入: {test1}, 输出: {longestPalindrome(test1)}") # bab
# 测试2: "cbbd" → "bb",长度为2
test2 = "cbbd"
print(f"输入: {test2}, 输出: {longestPalindrome(test2)}") # bb
# 测试3: "a" → "a",长度为1
test3 = "a"
print(f"输入: {test3}, 输出: {longestPalindrome(test3)}") # a
# 测试4: "ac" → "a" 或 "c",长度为1
test4 = "ac"
print(f"输入: {test4}, 输出: {longestPalindrome(test4)}") # a
# 测试5: "abacdfgdcaba" → "aba",长度为3
test5 = "abacdfgdcaba"
print(f"输入: {test5}, 输出: {longestPalindrome(test5)}") # aba
算法图解(以 "babad" 为例):
字符串: b a b a d
索引: 0 1 2 3 4
中心遍历:
i=0 (中心在 'b'):
奇数: expand(0,0) → 'b' → 长度1
偶数: expand(0,1) → 'b'≠'a' → 长度0
i=1 (中心在 'a'):
奇数: expand(1,1) → 'a' → 长度1
偶数: expand(1,2) → 'ab'≠'ba' → 长度0
i=2 (中心在 'b'):
奇数: expand(2,2) → 'b' → 'aba' → 找到长度3的回文!
左右都相等,继续扩散
偶数: expand(2,3) → 'ba' → 'abad' ≠ 'daba' → 长度0
最终结果: "aba" (索引1-3),长度3
关键点:
- 两种中心:单字符(奇数长度)和双字符间隙(偶数长度)
- 起始位置计算 :
start = i - (length - 1) // 2,同时适用于奇偶 - 退出循环时 :
left和right已经越界或不匹配,回文范围是(left+1, right-1)
时间复杂度分析:
- 外层循环:n 次遍历
- 内层扩散:每次最多 O(n)
- 总计:O(n²)