跳到主要内容

HJ85. 最长回文子串

题目描述

求小写字母字符串的最长回文子串长度。

子串:连续选择一段字符(可全选、可不选)。 回文串:从左往右读和从右往左读是相同的。

输入格式

一行上输入一个长度为 n、仅由小写字母构成的字符串。

输出格式

输出一个整数,表示字符串的最长回文子串的长度。

示例

示例 1

输入:

cdabbacc

输出:

4

说明: "abba" 是最长回文子串。

示例 2

输入:

a

输出:

1

解题思路

第一步:理解问题本质

回文串的核心特征是关于中心对称。例如:

  • 奇数长度回文 "abcba":中心是 'c'
  • 偶数长度回文 "abba":中心在两个 'b' 之间

这意味着,如果枚举每个可能的回文中心,向两边扩展,就能找到所有回文子串。

第二步:暴力解法

枚举所有子串,逐一判断是否为回文:

def brute_force(s):
n = len(s)
ans = 1
for i in range(n):
for j in range(i, n):
substr = s[i:j+1]
if substr == substr[::-1]:
ans = max(ans, len(substr))
return ans

时间复杂度:O(n³) —— 枚举 O(n²) 个子串,每个判断 O(n)。

第三步:最优解法 —— 中心扩展法

枚举每个字符作为回文中心,向两边扩展:

  1. 奇数长度:中心为单个字符 s[i],左右指针 left = right = i
  2. 偶数长度:中心为两个字符之间 s[i]s[i+1],左右指针 left = i, right = i+1

每次扩展判断 s[left] == s[right],相等则继续,否则停止。


完整代码实现

import sys


def longest_palindrome(s: str) -> int:
"""求字符串的最长回文子串长度(中心扩展法)"""
n = len(s)
if n <= 1:
return n

ans = 1

for i in range(n):
# 情况一:奇数长度回文,中心为 s[i]
left = right = i
while left >= 0 and right < n and s[left] == s[right]:
ans = max(ans, right - left + 1)
left -= 1
right += 1

# 情况二:偶数长度回文,中心在 s[i] 和 s[i+1] 之间
left, right = i, i + 1
while left >= 0 and right < n and s[left] == s[right]:
ans = max(ans, right - left + 1)
left -= 1
right += 1

return ans


if __name__ == "__main__":
for line in sys.stdin:
s = line.strip()
if s:
print(longest_palindrome(s))

示例推演

以输入 "cdabbacc" 为例:

枚举每个中心,扩展过程

中心 i奇数扩展偶数扩展更新后的 ans
0 ('c')"c" (1)1
1 ('d')"d" (1)1
2 ('a')"a" (1)1
3 ('b')"b" (1)"bb" (2)2
4 ('b')"b" (1)"bb" → "abba" (4)4
5 ('a')"a" (1)4
6 ('c')"c" (1)"cc" (2)4
7 ('c')"c" (1)4

结果:最长回文子串长度为 4("abba")。


复杂度分析

解法时间复杂度空间复杂度说明
暴力O(n³)O(n)枚举所有子串并判断
中心扩展O(n²)O(1)最优解法,只遍历一次
动态规划O(n²)O(n²)dp[i][j] 表示子串是否为回文
ManacherO(n)O(n)线性算法,面试进阶

n 为字符串长度


易错点总结

1. 只考虑奇数长度回文

# 错误!只处理了奇数长度
for i in range(n):
left = right = i
while ...:
# 只处理了以 s[i] 为中心的情况

解决:每个位置需要处理两种情况:奇数中心和偶数中心。

2. 边界越界

while left >= 0 and right < n and s[left] == s[right]:

注意:必须先判断 left >= 0right < n,再访问 s[left]s[right]

3. ans 初始值

ans = 1  # 至少单个字符是回文

如果初始化为 0,当输入为空字符串时会返回 0,但题目保证输入非空。

4. 字符串长度为 1

if n <= 1:
return n

单字符本身就是回文,直接返回 1。


扩展思考

Manacher 算法(O(n))

如果字符串长度很大(如 10⁵),中心扩展的 O(n²) 可能超时。Manacher 算法可以在 O(n) 时间内解决:

  1. 预处理:在字符间插入特殊字符(如 #),将偶数长度回文转为奇数长度
  2. 维护一个"最右回文边界",利用对称性减少重复计算
# Manacher 算法伪代码
def manacher(s):
# 预处理:插入 #
t = '#' + '#'.join(s) + '#'
n = len(t)
p = [0] * n # p[i] = 以 i 为中心的回文半径
center = right = 0
for i in range(n):
if i < right:
p[i] = min(right - i, p[2 * center - i])
while i - p[i] - 1 >= 0 and i + p[i] + 1 < n and t[i-p[i]-1] == t[i+p[i]+1]:
p[i] += 1
if i + p[i] > right:
center, right = i, i + p[i]
return max(p)

动态规划解法

def dp_solution(s):
n = len(s)
dp = [[False] * n for _ in range(n)]
ans = 1
for i in range(n-1, -1, -1):
dp[i][i] = True
for j in range(i+1, n):
if s[i] == s[j]:
dp[i][j] = dp[i+1][j-1] if j - i > 1 else True
if dp[i][j]:
ans = max(ans, j - i + 1)
return ans

相关题目

加载评论中...