滑动窗口的套路
滑动窗口是个啥
1.很显然,是个窗口,还能滑动
2.为啥要滑动?因为要在 长导轨 上匹配某个物体,并且不一定一开始就匹配上了,所以要左右滑动了
3.匹配方式有哪些?
- 匹配物 和 窗口 完全吻合
- 匹配物 是 窗口 的一部分,此时常常伴随着问题:什么时候窗口最小?
滑动窗口题怎么做
1.一个窗口是怎么表示的?左右边界。
2.于是核心问题就变成什么时候 右边界-左边界 最小?
- 固定左边界,右边界不断向右扩展(窗口扩大)
- 条件满足(如窗口全部包含了带匹配物),此时固定右边界,判断左边界是否可以右移(窗口是否可以缩小)
- 得到最终的窗口大小,多组匹配结果下取最小的窗口
/* 滑动窗口算法框架 */
void slidingWindow(string s, string t) {
unordered_map<char, int> need, window;
for (char c : t) need[c]++;
int left = 0, right = 0;
int valid = 0;
while (right < s.size()) {
// c 是将移入窗口的字符
char c = s[right];
// 右移窗口
right++;
// 进行窗口内数据的一系列更新
...
/*** debug 输出的位置 ***/
printf("window: [%d, %d)\n", left, right);
/********************/
// 判断左侧窗口是否要收缩
while (window needs shrink) {
// d 是将移出窗口的字符
char d = s[left];
// 左移窗口
left++;
// 进行窗口内数据的一系列更新
...
}
}
}
Leetcode
76. 最小覆盖子串
别看是hard,确实是套模板就完事了
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char,int> need, window;//模板,待匹配为need, 窗口为window
for(auto& c : t){
need[c]++;//模板,待匹配的都记录下来(**谁+出现几次**),方便查询
}
int left=0, right=0;//模板,左右边界
int cnt = 0;//自定义,正好匹配的条件
int start = 0;//自定义,结果对应的起始索引
int minLen = INT_MAX;//自定义,最小字串肯定要记录最小值
while(right < s.size()){
char tmp = s[right];//模板
right++;//模板
if(need.count(tmp) != 0){
window[tmp]++;//自定义,窗口的更新
//窗口内的个数和
if(window[tmp] == need[tmp]) cnt++; //自定义,匹配完成的条件
}
while(cnt == need.size()){
if(right-left < minLen){
minLen = right - left;
start = left;
}
char tmp1 = s[left];//模板
left++;//模板
//左边界右移
if(need.count(tmp1) != 0){
window[tmp1]--;
if(window[tmp1] < need[tmp1]) cnt--;//窗口内的tmp1个数小于所需要的,肯定就不满足了,cnt--
}
}
}
if(minLen < INT_MAX){
return s.substr(start, minLen);
}else{
return "";
}
}
};