76. 最小覆盖子串(困难)

Blind 75 › 76. 最小覆盖子串(困难) (第 4 章)
文章工具

题目

题目描述

给定两个只含大小写英文字母的字符串 s 和 t,请在 s 中找出一段 长度最短的连续子串,使得这段子串里每个字符出现的次数,都不少于该字符在 t 中的出现次数。如果不存在这样的子串,返回空字符串 ""。题目保证最短答案唯一。

自造示例

st输出说明
"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)

解法

🔒

本篇为付费内容

您已阅读试读部分,购买后即可解锁全文。

⚠️ 本站内容已做唯一性标记并受版权保护,未经授权禁止转载,侵权必究。