647. 回文子串(中等)
题目
给定一个字符串 s,统计它一共有多少个回文子串。子串必须由连续字符组成;不同位置区间的回文单独计数,即使内容完全相同。
回文就是正着读、反着读一样的字符串,例如 "aba"、"bb"、单个字符 "a" 都算回文。
自造示例:s = "abba" → 6,分别是 "a"、"b"、"b"、"a"、"bb"、"abba"。
再看一个:s = "aba" → 4,分别是 "a"、"b"、"a"、"aba"。
约束:长度 1 ≤ n ≤ 1000;只含小写字母。
思路
一句话:回文关于中心对称,枚举所有可能的中心并向两侧扩展,每对齐一层就算出一个回文。
最直白的做法:枚举所有子串 s[i..j](约 O(n²) 个),再对每个子串 O(n) 判断是否回文,总共 O(n³)。n = 1000 时接近 109 量级,会超时;而且大量子串翻来覆去地重复同一套比较。
关键观察:回文不是“任意两个字符配对”,而是围绕一个唯一轴心镜像相等。只要确定了轴心,就能把“判断是否回文”和“继续往外找新的回文”合并成一次扫描;一旦两端失配,再往外也不可能回文,直接停。
中心分两类:
- 奇数长度:轴落在某个字符上,初始左右指针同为
(i, i)。 - 偶数长度:轴落在
s[i]与s[i+1]之间的缝隙,初始为(i, i+1)。
共有 2n−1 个中心,每个中心最多向外扩展 O(n) 次,总时间 O(n²)、空间 O(1)。比暴力少一个维度,且无需额外数组。
同一个“大回文由小回文推出”的信息也能写成 DP:dp[i][j] 表示 s[i..j] 是否回文,时间也是 O(n²)。本文主解法选代码最短、空间 O(1) 的中心扩展;DP 与线性 Manacher 见「扩展三」。
解法
封装一个函数 expand(l, r):只要 s[l] == s[r] 且两端都没越界,就说明又找到一个回文,计数加一,然后左指针左移、右指针右移;失配或越界立即停止。
外层对每个位置 i 调用两次:
expand(i, i):统计以字符s[i]为中心的奇数长度回文。expand(i, i+1):统计以i与i+1之间缝隙为中心的偶数长度回文。
以 s = "abba" 为例:
| 中心 | 实际扩出的回文 | 个数 |
|---|---|---|
(0,0) 奇 | "a" | 1 |
(0,1) 偶 | 无(a、b 不等) | 0 |
(1,1) 奇 | "b" | 1 |
(1,2) 偶 | "bb"、"abba" | 2 |
(2,2) 奇 | "b" | 1 |
(2,3) 偶 | 无(b、a 不等) | 0 |
(3,3) 奇 | "a" | 1 |
合计 1+0+1+2+1+0+1 = 6。注意 i = n−1 时 (i, i+1) 的右端越过右边界,while 一进来就退出、自然计 0,不必特判。
下图把上面 2 个步骤串成流程,并逐步演示:


本篇为付费内容
您已阅读试读部分,购买后即可解锁全文。
⚠️ 本站内容已做唯一性标记并受版权保护,未经授权禁止转载,侵权必究。
还没有评论,来说两句?