图解题库 / 字符串 · 回文

5. 最长回文子串

中等 含交互动画

学完这道你应该能: 说清它为什么用「回文」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

题目描述

找出字符串里最长的回文子串(连续)。

s = "babad"
输出 = "bab"(或 "aba",都对)

思路解析

所有子串有 n² 个,每个判回文还要 O(n),总共 O(n³)。换个思路:回文一定有个中心,从中心往两边扩,能省一个量级。

对每个中心,左右指针一起向外走,只要 s[l]==s[r] 就继续扩;一旦不等或越界就停,记录这段长度。中心有两种:单字符(奇回文)和两字符之间(偶回文),都试一遍取最长。

以下标 1 的 a 为中心:从中心 a(下标 1)开始,l=r=1。单字符本身就是长度 1 的回文,向两边扩。

向外扩 · b == b ✓:l 退到 0(b)、r 进到 2(b),s[0]==s[2],是回文!当前回文 "bab",长度 3。继续往外扩。

再扩 · 越界,停:l 再退就到 −1 越界,停止。以 a 为中心扩出的最长回文是 "bab"(长度 3)。

其它中心 · 都不更长:再试其它中心,比如以下标 2 为中心能扩出 "aba"(也是 3),但没有更长的。最终答案长度 3

抓住"回文关于中心对称"这一点,就能把"判断 + 枚举"合二为一:从中心往外扩,扩到哪算到哪。回文子串计数、最长回文子序列都和它相关。

参考代码(Python)

Python
1def expand(l, r):                      # 从中心向两边扩
2    while l >= 0 and r < n and s[l] == s[r]:
3        l -= 1; r += 1
4    return l + 1, r - 1                # 回文区间(扩过头要收回一格)
5best = (0, 0)
6for i in range(n):
7    for a, b in (expand(i, i), expand(i, i+1)):   # 奇 + 偶 中心
8        if b - a > best[1] - best[0]: best = (a, b)

复杂度分析

  • 时间复杂度:O(n²) —— n 个中心 × 每个最多扩 n
  • 空间复杂度:O(1) —— 只用几个指针

套路模板

记住骨架:一个 expand 函数、每个位置试奇偶两种中心、相等就向外扩。回文子串数(647)就是把"记录最长"换成"累加每次扩成功的次数"。

Python
1def expand(l, r):
2    while l >= 0 and r < n and s[l] == s[r]:   # 两边相等就扩
3        l -= 1; r += 1
4    return r - l - 1                  # 回文长度
5for i in range(n):
6    odd  = expand(i, i)              # 奇中心
7    even = expand(i, i + 1)         # 偶中心

易错点

  • 只考虑奇数长度中心 → ✅ 奇 (i,i) 和偶 (i,i+1) 都要试("abba" 这种偶回文中心在两字符之间)
  • 区间边界算错 → ✅ while 停后回文是 [l+1, r-1](循环退出时 l、r 已各多走一步)

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →647. 回文子串 ← 返回题库