76.最小覆盖子串
解题思路:滑动窗口 + 哈希表
这是滑动窗口的经典题型,我们的目标是在字符串 s
中寻找一个最小长度的窗口,该窗口内包含 t
的全部字符(包括数量)。
思路步骤:
-
使用两个哈希表:
need
:记录t
中每个字符的需求数量;window
:记录当前窗口中每个字符的出现次数。
-
使用双指针
left
和right
维护一个动态窗口[left, right)
。right
扩大窗口;- 当窗口满足条件后,
left
开始收缩窗口以寻找更短的解。
-
使用
valid
变量表示当前窗口中满足要求的字符种类数。- 每当
window[c] == need[c]
,就说明字符c
满足了需求。
- 每当
-
在每次窗口满足条件时尝试更新最短子串长度。
完整代码(C++)
class Solution {
public:string minWindow(string s, string t) {unordered_map<char, int> need, window;int left = 0, right = 0;int start = 0;int len = 1e9; // 初始设为一个很大的值int valid = 0;// 统计目标字符频率for(char c : t){need[c]++;}while(right < s.size()){// 扩大窗口char c = s[right++];if(need.count(c)){window[c]++;if(window[c] == need[c]){valid++;}}// 尝试缩小窗口while(valid == need.size()){// 更新最小覆盖子串if(right - left <= len){len = right - left;start = left;}char d = s[left++];if(need.count(d)){if(window[d] == need[d]){valid--;}window[d]--;}}}return len == 1e9 ? "" : s.substr(start, len);}
};
关键细节说明
点 | 解释 |
---|---|
need.count(c) | 判断字符是否是目标字符 |
valid 的维护 | 只有当字符数量恰好满足才算“有效” |
window[c]++ / -- | 始终更新当前窗口的字符频率 |
len == 1e9 | 用于判断是否找到合法子串 |
复杂度分析
-
时间复杂度:
O(n)
每个字符最多进窗口一次、出窗口一次,因此整体为线性时间。 -
空间复杂度:
O(|t| + |s|)
两个哈希表用于存储字符频率。