题目描述:
给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字符的最小子串。
示例:
输入: S = “ADOBECODEBANC”, T = “ABC”
输出: “BANC”
说明:
如果 S 中不存这样的子串,则返回空字符串 “”。
如果 S 中存在这样的子串,我们保证它是唯一的答案。
方法1:使用滑动窗口
主要思路:
(1)滑动窗口的通常做法,将窗口从头开始,先右侧边界扩展,扩大窗口,然后判断当前窗口是否满足要求,若是不满足,则接着扩大右侧边界,若当前窗口满足某种条件,则开始变化左侧窗口边界,减小窗口,直到窗口不再满足条件,然后再开始接着扩展右侧边界;
(2)然后,根据不同的题目内容,构造不同的窗口判断条件;
(3)这里使用了两个 unordered_map,既 unordered_map<char,int> need,win; 在need中存储需要判断的字符串 t 内的字符的情形,在win中,用来更新,存储 s 中的内容,直到win中的内容满足了某种要求,这里使用变量valid来统计这种要求,既valid==need.size(),既当前窗口内具有了 t 中的全部内容,可以进一步的减小窗口,既变化窗口左边界,直到该要求不再满足;
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char,int> need,win;
for(char ch:t){
need[ch]++;
}
int left=0;
int right=0;
int start=0;
int len=INT_MAX;
int valid=0;
while(right<s.size()){
char ch=s[right++];
if(need.count(ch)){
win[ch]++;
//注意这里使用的是==,不是>=,是为了保证valid和need中的大小的一致性,避免重复统计
if(win[ch]==need[ch])
++valid;
}
while(valid==need.size()){
if(right-left<len){//更新需要的子字符串的大小和位置
start=left;
len=right-left;
}
ch=s[left++];
if(need.count(ch)){
//减之前若相等,则减值后不再相等,这里使用==作为判断条件,同时避免了win[ch]>need[ch]的情形
if(win[ch]==need[ch])
--valid;
--win[ch];
}
}
}
return len==INT_MAX?"":s.substr(start,len);//根据是否找到子字符串,返回结果
}
};