2.8滑动窗口专题:最小覆盖子串
1. 题目链接
LeetCode 76. 最小覆盖子串
2. 题目描述
给定字符串 s
和 t
,要求找到 s
中最小的窗口,使得该窗口包含 t
的所有字符(包括出现次数)。若不存在,返回空字符串。
示例:
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
(最短窗口包含 A
、B
、C
,且长度最短)。
3. 示例分析
以 s = "ADOBECODEBANC", t = "ABC"
为例:
-
滑动窗口法:
right
移动到索引 5 时,窗口"ADOBEC"
包含A
、B
、C
,记录长度为 6。- 继续移动
right
到索引 10,窗口缩小为"BANC"
,长度为 4,更新为最终结果。
-
暴力枚举法:
- 枚举所有子串,例如
[0,5]
、[0,6]
、[9,12]
,逐个检查是否包含t
的所有字符。
- 枚举所有子串,例如
4. 算法思路
滑动窗口法:
- 哈希表统计:
hash1
统计t
中字符的出现次数。hash2
统计当前窗口内字符的出现次数。
- 动态窗口调整:
- 右指针扩展:将字符加入窗口,若其出现次数等于
t
中的次数,增加有效计数count
。 - 左指针收缩:当窗口包含
t
的所有字符时,尝试缩小窗口并更新最小长度。
- 右指针扩展:将字符加入窗口,若其出现次数等于
- 结果记录:每次窗口满足条件时,检查是否为最短窗口。
暴力枚举法:
- 枚举所有可能的子串起点
i
和终点j
(i ≤ j
),检查子串是否包含t
的所有字符。
5. 边界条件与注意事项
- 字符重复性:窗口需满足
t
中字符的出现次数,而不仅是存在性。- 例如
t = "AA"
,窗口必须包含至少两个A
。
- 例如
- 无效输入:若
s
长度小于t
,直接返回空。 - 哈希表初始化:需覆盖所有 ASCII 字符(代码中使用
hash[128]
)。 - 最小窗口更新:需在每次窗口合法时实时更新,避免遗漏更优解。
6. 代码实现
class Solution {
public:
string minWindow(string s, string t)
{
int ns = s.size(), nt = t.size();
if (ns < nt) return "";
int hash1[128] = {0}; // 统计t的字符频次
int kinds = 0; // t中不同字符的种类数
for (char ch : t) {
if (hash1[ch]++ == 0) kinds++;
}
int hash2[128] = {0}; // 窗口内字符频次
int left = 0, count = 0, min_len = INT_MAX, begin = -1;
for (int right = 0; right < ns; right++) {
char in_ch = s[right];
hash2[in_ch]++;
// 当窗口内该字符频次首次满足t的要求时,增加count
if (hash2[in_ch] == hash1[in_ch]) count++;
// 当窗口包含t的所有字符时,尝试缩小窗口
while (count == kinds) {
// 更新最小窗口
if (right - left + 1 < min_len) {
min_len = right - left + 1;
begin = left;
}
// 移除左边界字符
char out_ch = s[left++];
// 若移除后导致频次不足,减少count
if (hash2[out_ch]-- == hash1[out_ch]) count--;
}
}
return (begin == -1) ? "" : s.substr(begin, min_len);
}
};
7. 暴力枚举法与滑动窗口法对比图表
对比维度 | 暴力枚举法 | 滑动窗口法 |
---|---|---|
核心思想 | 枚举所有子串,逐一检查是否包含 t 的所有字符。 | 动态维护窗口,仅在窗口不满足条件时扩展,满足条件时收缩以寻找最优解。 |
时间复杂度 | O(n² * m)(n为s 长度,m为t 长度,需遍历所有子串并检查字符频次)。 | O(n)(每个字符被左右指针各访问一次)。 |
空间复杂度 | O(1)(使用固定大小的哈希表)。 | O(1)(哈希表大小为128,常数空间)。 |
实现方式 | 双重循环枚举子串,内层循环统计字符频次。 | 单层循环扩展右指针,内层循环收缩左指针。 |
适用场景 | 极小规模数据(n ≤ 100)。 | 大规模数据(n ≤ 1e5)。 |
优点 | 逻辑简单,直接穷举所有可能性。 | 时间复杂度最优,适用于大规模输入。 |
缺点 | 数据规模大时性能极差(n=1e4时需1e8次操作)。 | 需精确维护哈希表状态(如count 增减逻辑)。 |