先从左往右找到第一个最大覆盖子串
然后在保持全覆盖的基础上,进入从左侧缩小窗口的循环
从左侧遍历考察,保存start、len的条件下,考虑能不能删除左侧元素
如果删除某个元素之后,不再满足全覆盖
则再次从right开始向右遍历直到满足全覆盖,才能进入从左侧缩小窗口的循环
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char,int>need,window;
for(char c : t) need[c]++;
//need计算各个字符出现的次数
int left = 0,right = 0;
int valid = 0;
//记录最小覆盖子串的起始索引以及长度
int start = 0,len = INT_MAX;
while(right < s.size()){
//左开右闭
char c = s[right];
//扩大窗口
right++;
if(need.count(c)){
//S中找到了C
window[c]++;
if(window[c] == need[c]){
valid++;
}
}
//循环结束后,从0到s.size() - 1遍历了S
//记录了S中出现的T中的字符的个数(valid)
while(valid == need.size()){
//在S串满足T串的全部字符
if(right - left < len){
start = left;
len = right - left;
}
char d = s[left];
left++;
if(need.count(d)){
if(window[d] == need[d]){
valid--;
}
window[d]--;
}
}
}
return len == INT_MAX ? "" : s.substr(start,len);
}
};