题目描述
思路解析动画文字版
记住「枚举两端字符 c → 取它首尾下标 l/r → 中间不同字符种数就是贡献」,下面每帧都在套它。
先把回文长相看清:比如两端都是 a,中间夹 b 就是 aba,夹 c 就是 aca。同一个 a?a 只算一次,所以中间字符要去重。下面逐个枚举「两端字符」。
轮到把 a 当两端。先找它第一次出现的位置:下标 0。这是回文左端能放的最靠前的地方。
再找 a 最后一次出现的位置:下标 6。右端放这里最靠后,左右端之间的范围最大,能罩住最多的中间字符。
两端相距 6,大于等于 2,中间至少夹得下一个字符,能凑成 a?a。接下来扫 (0, 6) 之间,数出有几种不同的中间字符。
中间这位是 a,是个新字符,记进集合:{a}。它对应回文 aaa,是一种新的回文。
中间这位是 b,是个新字符,记进集合:{a, b}。它对应回文 aba,是一种新的回文。
中间这位是 c,是个新字符,记进集合:{a, b, c}。它对应回文 aca,是一种新的回文。
中间这位是 c,前面已经见过,去重不重复计——因为 aca 这种回文只能算一次。集合保持 {a, b, c}。
中间这位是 b,前面已经见过,去重不重复计——因为 aba 这种回文只能算一次。集合保持 {a, b, c}。
数完了:中间有 3 种不同字符,所以两端为 a 的回文有 3 个(aaa、aba、aca)。累加进答案,ans = 3。
轮到把 b 当两端。先找它第一次出现的位置:下标 2。这是回文左端能放的最靠前的地方。
再找 b 最后一次出现的位置:下标 5。右端放这里最靠后,左右端之间的范围最大,能罩住最多的中间字符。
两端相距 3,大于等于 2,中间至少夹得下一个字符,能凑成 b?b。接下来扫 (2, 5) 之间,数出有几种不同的中间字符。
中间这位是 c,是个新字符,记进集合:{c}。它对应回文 bcb,是一种新的回文。
中间这位是 c,前面已经见过,去重不重复计——因为 bcb 这种回文只能算一次。集合保持 {c}。
数完了:中间有 1 种不同字符,所以两端为 b 的回文有 1 个(bcb)。累加进答案,ans = 4。
轮到把 c 当两端。先找它第一次出现的位置:下标 3。这是回文左端能放的最靠前的地方。
再找 c 最后一次出现的位置:下标 4。右端放这里最靠后,左右端之间的范围最大,能罩住最多的中间字符。
两端 c 的首尾下标相距只有 1,小于 2,中间夹不下任何字符,凑不成 c?c,直接跳过。ans 不变,还是 4。
26 个字母都当过两端枚举完,累加得到 4 种不同的长度 3 回文:aaa、aba、aca、bcb。回头看,我们没枚举任何子序列,只对每个字符取首尾下标、数中间去重字符,一遍就数清了。
边界:没有重复字符返回 0;全同字符只贡献一种;串长不足 3 也是 0。
两个高频追问:取首尾是为了范围最大不漏种、26 来自固定字母表。
参考代码
class Solution: def countPalindromicSubsequence(self, s: str) -> int: ans = 0 for c in set(s): l = s.find(c) r = s.rfind(c) if r - l >= 2: ans += len(set(s[l + 1:r])) return ans复杂度
- 时间:O(26·n),26 个字母各扫一遍中间区间,n 为串长,常数 26 即字母表大小
- 空间:O(1),first/last 各 26 个、中间集合最多 26 个,都是常数
易错点
面试追问把动画讲成自己的话
追问为什么两端要取 first 和 last,而不是任意两个相同字符?
追问复杂度里的 26 是怎么来的?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
相等行列对
LeetCode 2352 · 中等 · 沿着 哈希套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题