76. 最小覆盖子串(困难)
Blind 75 › 76. 最小覆盖子串(困难) (第 4 章)
题目
题目描述
给定两个只含大小写英文字母的字符串 s 和 t,请在 s 中找出一段 长度最短的连续子串,使得这段子串里每个字符出现的次数,都不少于该字符在 t 中的出现次数。如果不存在这样的子串,返回空字符串 ""。题目保证最短答案唯一。
自造示例
| s | t | 输出 | 说明 |
|---|---|---|---|
"ABACD" | "ABD" | "ABAC" | 需要 A、B、D;"ABAC" 是唯一最短覆盖窗口。 |
"xyxy" | "x" | "x" | 单字符窗口已经足够。 |
"abc" | "abcd" | "" | s 中根本没有 d,无法覆盖。 |
约束
- 1 ≤ m, n ≤ 10⁵,其中 m =
s.length,n =t.length。 s和t只由大小写英文字母组成。- 最短答案唯一。
思路
一句话本质
用一张「需求表」记录 t 还缺哪些字符、各缺多少次;右指针扩张让窗口达标,左指针收缩让窗口最短,再用「已满足的字符种类数」判断是否覆盖。
最直白的做法:枚举所有子串
枚举 s 的所有左右端点,得到每个子串后,再逐个统计它是否覆盖 t。如果每次重新扫描,时间复杂度是 O(m³);即使优化成边枚举边计数,也要 O(m²)。当 m = 10⁵ 时,O(m²) 已经到达 10¹⁰ 级别,明显不可行。
关键观察:覆盖性随窗口移动是单调的
当右端点向右移动时,窗口只会变长,覆盖能力只会增强或不变;当左端点向右移动时,窗口只会变短,覆盖能力只会减弱或不变。因此:
- 某个右端点一旦让窗口「刚好覆盖」,左端点就可以一路右移,直到窗口「差一点就不覆盖」。
- 右端点不需要回退:更靠右的答案只需要继续扩展新的右端点,再配合左端点收缩即可。
选定做法
采用「滑动窗口 + 需求表」。一个右指针只负责扩展,一个左指针只负责收缩;用 matched 表示「t 中已经满足频次要求的字符种类数」,当 matched 等于 t 中不同字符的总数时,当前窗口就是合法的。
| 做法 | 判断一次是否覆盖 | 总代价 |
|---|---|---|
| 枚举所有子串并重新计数 | O(m) | O(m³) |
| 滑动窗口 + 需求表 | O(1) 均摊 | O(m + n) |
解法本篇为付费内容
您已阅读试读部分,购买后即可解锁全文。
⚠️ 本站内容已做唯一性标记并受版权保护,未经授权禁止转载,侵权必究。
本篇为付费内容
您已阅读试读部分,购买后即可解锁全文。
⚠️ 本站内容已做唯一性标记并受版权保护,未经授权禁止转载,侵权必究。
还没有评论,来说两句?