滑动窗口是双指针一个比较经典的应用,分为固定窗口和变动窗口,
对于变动窗口,其执行过程可以概括为:
1.初始left=0;right=0
2.向右移动right
,扩大窗口,寻找可行解
3.找到可行解后,向右移动left
,收缩窗口,优化可行解
4.循环执行第2步和第3步,直到right到达边界
变化滑动窗口:76最小覆盖子串
class Solution {
public:
//滑动窗口思想:每轮先找到可行解,然后优化可行解
string minWindow(string s, string t) {
//结果
int len=s.size()+1,start=0;
//统计t中的字符
map<char,int>mp;
for(auto&c:t)
if(mp.find(c)==mp.end())
mp[c]=1;
else
mp[c]++;
//滑动窗口[left,right]
int left=0,right=0;
while(right<s.size()){
char c=s[right];
//处理当前字符
if(mp.find(c)!=mp.end()){
mp[c]--;
}
//如果当前是可行解,那么优化可行解
while(check(mp)){
//记录可行解
if(right-left+1<len){
len=right-left+1;
start=left;
}
char c2=s[left];
//优化可行解
if(mp.find(c2)!=mp.end()){
mp[c2]++;
}
left++;
}
right++;
}
return len<=s.size()?s.substr(start,len):"";
}
bool check(map<char,int>&mp){
for(auto&item:mp)
if(item.second>0)
return false;
return true;
}
};
固定滑动窗口:567字符串的排列
此题利用长度为26的vector,来存放字符信息,非常巧妙。因为可以直接利用==
符号,判断两个vecoter内容是否相同。
注意:本题不宜使用两个map,然后用==
判断内容是否相同。因为map2[xx]=0时,仍然存留在map2中,此时如果map1中没有xx
,则==
结果为false。
class Solution {
public:
//固定大小的滑动窗口
bool checkInclusion(string s1, string s2) {
if(s2.size()<s1.size())
return false;
vector<int>cs1(26,0);
vector<int>cs2(26,0);
int len=s1.size();
for(int i=0;i<len;i++){
cs1[s1[i]-'a']++;
cs2[s2[i]-'a']++;
}
if(cs1==cs2)
return true;
for(int i=0;i+len<s2.size();i++){
cs2[s2[i+len]-'a']++;
cs2[s2[i]-'a']--;
if(cs1==cs2)
return true;
}
return false;
}
};
固定滑动窗口:438找到字符串中所有字母异位词
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
if(s.size()<p.size())
return {};
vector<int>ans;
//记录字符
vector<int>char_s(26,0);
vector<int>char_p(26,0);
//初始化
for(auto&c:p)
char_p[c-'a']++;
int len=p.size();
for(int i=0;i<len;i++)
char_s[s[i]-'a']++;
if(char_p==char_s)
ans.emplace_back(0);
//滑动窗口
for(int i=len;i<s.size();i++){
char_s[s[i-len]-'a']--;
char_s[s[i]-'a']++;
if(char_s==char_p)
ans.emplace_back(i-len+1);
}
return ans;
}
};
固定滑动窗口:3无重复字符的最长子串
注意:这一题的字符可以是数字、字母、符号、空格,因此vector的长度应该为ASCII表的长度,即128
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int ans=0;
vector<int>chars(128,-1); //记录每个字符出现的位置
int left=0,right=0; //滑动窗口范围[left,right]
while(right<s.size()){
if(chars[s[right]]!=-1){
ans=max(ans,right-left);
while(left<chars[s[right]]+1){ //收缩左侧窗口
chars[s[left]]=-1;
left++;
}
}
chars[s[right]]=right;
right++;
}
ans=max(ans,right-left);
return ans;
}
};