647. 回文子串

中等 含交互动画

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

AI 私教 · 就着本题动画讲
卡住了不用硬扛,按 8 步把这题真正走通。
从读题、试解、找法到手写代码,边问边打勾,适合第一次系统学算法的同学。

题目描述

统计字符串中回文子串的个数(内容相同但起止位置不同算多个)。

s = "aaa"
输出 = 6

思路解析

最直接的笨办法:枚举起点和终点(n² 个子串),每个子串再花 O(n) 判断是不是回文,合起来 O(n³)。换个思路:回文一定有个中心,从中心往两边扩,能省一个量级。

转折:为什么成立——回文关于中心镜像对称,知道中心就能向外验证。对每个中心,l、r 一起往外走,只要 s[l]==s[r] 就计数 +1(发现一个新回文)并继续;一旦不等或越界就停。中心有两种:单字符(奇回文)和两字符之间(偶回文),都要数。

奇中心 · 下标 1 的 a:从中间 a(下标 1)出发,l=r=1。奇中心第一步必成立:单字符 "a" 就是回文,count = 1。继续往两边扩。

奇中心 1 · 向外扩 a==a:l 退到 0、r 进到 2,s[0]==s[2],扩成功!发现回文 "aaa",count = 2。这个奇中心已贡献 2 个,再往外扩。

奇中心 1 · l 越界,停:转折(负例):l 再退一步就到 −1 越界,扩展停止。以下标 1 为奇中心一共数到 2 个回文。换下一个中心。

奇中心 · 下标 0 的 a:换成下标 0 的 a 当奇中心,l=r=0,单字符 "a" 又是一个回文,count = 3。试着往外扩。

奇中心 0 · l 越界,停:左边已经到头,l 退一步就越界,停。最左那个 a 当中心只能扩出它自己。下标 2 的 a 同理也只贡献 1 个(对称)。

偶中心 · 下标 0、1 之间:偶中心登场:以下标 0、1 之间为中心,l=0、r=1,s[0]==s[1],扩成功,发现 "aa",count = 4。偶回文只能从这种中心找到。

偶中心 0-1 · l 越界,停:l 再退就越界,停。这个偶中心数到 1 个 "aa"。还剩最后一个偶中心:下标 1、2 之间。

偶中心 · 下标 1、2 之间:最后一个偶中心(下标 1、2 之间):l=1、r=2,s[1]==s[2],又一个 "aa",count = 5。再扩 l 到 0、r 到 3 时 r 越界,停。

所有中心累计 · 共 6 个:把每个奇中心、偶中心扩出的回文全加起来:3 个 "a" + 2 个 "aa" + 1 个 "aaa" = 6。这就是答案。

最长回文子串(LC5)是「记录最长」,回文子串(647)是「累加计数」——同一个中心扩展骨架,只换「扩成功时做什么」就解决不同问题。这就是掌握套路的威力。

参考代码(Python)

Python
1n = len(s)
2count = 0
3def expand(l, r):                      # 从中心向两边扩并计数
4    nonlocal count
5    while l >= 0 and r < n and s[l] == s[r]:  # 两端相等才继续
6        count += 1                     # 每扩成功一次 = 一个回文
7        l -= 1; r += 1
8for i in range(n):
9    expand(i, i)                       # 奇中心: 单字符
10    expand(i, i + 1)                   # 偶中心: 两字符之间
11return count

复杂度分析

  • 时间复杂度:O(n²) —— n 个位置 × 每个中心最多扩 n/2 步
  • 空间复杂度:O(1) —— 只用 l、r 和一个计数器

套路模板

记住骨架:奇偶中心都试、相等就扩、扩成功就收集。把「收集」换成计数、记最长、记区间,就分别解 647、5 等回文题。

Python
1def expand(l, r):
2    while l >= 0 and r < n and s[l] == s[r]:   # 两边相等就扩
3        count += 1                     # 收集: 计数(或记最长/区间)
4        l -= 1; r += 1
5for i in range(n):
6    expand(i, i)                       # 奇中心
7    expand(i, i + 1)                  # 偶中心

易错点

  • 错误写法:只数奇中心 expand(i,i)正确写法:奇 (i,i) 和偶 (i,i+1) 两种中心都要扩("aa" 这类偶回文中心落在两字符之间,只数奇中心会漏掉它们,结果偏少)
  • 错误写法:扩成功后忘了 count += 1,或在 while 外才 +1正确写法:每次 s[l]==s[r] 成立就立刻 count += 1(计数要绑在「扩成功」这一刻:每多对齐一层就是一个新回文,放 while 外会少算或算错)

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

下一题 →14. 最长公共前缀 ← 返回题库