滑动窗口的代码模板
#window表示当前窗口
unordered_map<char,int> window;
#need表示窗口可以移动时需要满足的条件,某些情况下可以不写
unordered_map<char,int> need;
#fast指向当前window的右边界,slow指向window的左边界,区间左闭右开
int fast=0,slow=0;
#valid记录window中满足need的个数
int valid=0;
#更新need
for(auto i:t)
need[i]++;
while(fast<s.size()){
char c=s[fast];
//s[fast]加入window后,fast立刻++,这里说明window是左闭右开的
fast++;
if(need.count(c)){
window[c]++;
if(window[c]==need[c])
valid++;
}
#valid的大小等于need.size(),说明当前window已经满足条件
while(valid==need.size()){
if(满足题意){
...
}
#更新窗口数据
char c=s[slow];
slow++;
if(need.count(c)){
if(window[c]==need[c])
valid--;
window[c]--;
}
}
}
以上代码都是固定的,需要改动的部分都在 ... 处,下面我们结合具体的题目来看一下。
以leetcode上的例题为例,按照输入个数分为两类
1、两个输入:
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
unordered_map<char,int> need;
unordered_map<char,int> window;
vector<int> ans;
for(auto i:p)
need[i]++;
int valid=0,fast=0,slow=0;
while(fast<s.size()){
char f=s[fast];
fast++;
if(need.count(f)){
window[f]++;
if(window[f]==need[f])
valid++;
}
while(valid==need.size()){
//当下面条件成立时,说明当前窗口内的是异位词,需添加到ans中
if(fast-slow==p.size())
ans.push_back(slow);
char str=s[slow];
slow++;
if(need.count(str)){
if(need[str]==window[str])
valid--;
window[str]--;
}
}
}
return ans;
}
};
class Solution {
public:
bool checkInclusion(string s1, string s2) {
unordered_map<char,int> window;
unordered_map<char,int> need;
for(auto i:s1)
need[i]++;
int fast=0,slow=0,valid=0;
while(fast<s2.size()){
char c=s2[fast];
fast++;
if(need.count(c)){
window[c]++;
if(window[c]==need[c])
valid++;
}
while(valid==need.size()){
/
if(fast-slow==s1.size())
return true;
char d=s2[slow];
slow++;
if(need.count(d)){
if(window[d]==need[d])
valid--;
window[d]--;
}
}
}
return false;
}
};
class Solution {
public:
bool checkInclusion(string s1, string s2) {
unordered_map<char,int> window;
unordered_map<char,int> need;
for(auto i:s1)
need[i]++;
int fast=0,slow=0,valid=0;
while(fast<s2.size()){
char c=s2[fast];
fast++;
if(need.count(c)){
window[c]++;
if(window[c]==need[c])
valid++;
}
while(valid==need.size()){
if(fast-slow==s1.size())
return true;
char d=s2[slow];
slow++;
if(need.count(d)){
if(window[d]==need[d])
valid--;
window[d]--;
}
}
}
return false;
}
};
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char,int> window;
unordered_map<char,int> need;
int fast=0,slow=0,start=0,len=INT_MAX,valid=0;
for(auto i:t)
need[i]++;
while(fast<s.size()){
char c=s[fast];
fast++;
if(need.count(c)){
window[c]++;
if(window[c]==need[c])
valid++;
}
while(valid==need.size()){
///
if(len>fast-slow){
len=fast-slow;
start=slow;
}
///
char c=s[slow];
slow++;
if(need.count(c)){
if(window[c]==need[c])
valid--;
window[c]--;
}
}
}
return INT_MAX==len?"":s.substr(start,len);
}
};
2、一个输入
一个输入相较于两个输入比较简单,因为不需要通过need来判断当前window是否需要移动
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char,int> window;
int fast=0,slow=0,ans=0;
while(fast<s.size()){
char c=s[fast];
fast++;
window[c]++;
//window[c]>1说明当前window内有重复元素,需要移除,来保证window内的元素都是唯一的
//这时,window就需要移动
while(window[c]>1){
window[s[slow]]--;
slow++;
}
//当前window内的元素都是唯一的,可以更新ans
ans=max(ans,fast-slow);
}
return ans;
}
};
class Solution {
public:
int totalFruit(vector<int>& fruits) {
unordered_map<int,int> window;
int fast=0,slow=0,count=0;
while(fast<fruits.size()){
int c=fruits[fast];
fast++;
window[c]++;
//说明window里有超过两种元素,窗口需要滑动,slow需要向右移动
while(window.size()>2){
int d=fruits[slow];
window[d]--;
if(window[d] == 0 )
window.erase(d);
slow++;
}
count=max(count,fast-slow);
}
return count;
}
};
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int ans=INT_MAX;
int fast=0,slow=0;
//记录窗口内元素总和
int sum=0;
while(fast<nums.size()){
sum+=nums[fast];
fast++;
while(sum>=target){
ans=min(ans,fast-slow);
sum-=nums[slow];
slow++;
}
}
return ans==INT_MAX?0:ans;
}
};