滑动窗口的逻辑比较简单,但是细节比较复杂,其中最难的地方在于
如何判断左边窗口缩小的时机和在何处更新答案
下面对活动窗口的逻辑做一个综述;
(1),定义两个map,用作两个计数器,一个用来计算目标串的信息,另一个用来计算窗口串的信息,分别记作need和window。
(2) 定义左右指针和valid变量,用来记录窗口中符合要求的时机。当valid==need.size()的时候就要收缩左侧指针,例如leetcode第76题。
(3)逻辑在于,现在字符串中找到一个可行解,当找到这个可行解的时候就收缩左侧指针,然后比较收缩后的答案和目标答案是不是一样的,然后继续扩大右侧指针,再比较;如果满足就扩大左指针,不满足就扩大右指针,左右指针交替按照条件扩大,直到右侧指针到字符串的结尾。把leetcode上的几道题总结如下。
- leetcode.76
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char,int> need,window;
for(char c:t) need[c]++;//第一个计数器,计算目标串中有多少个目标字符;
int left=0;
int right=0;
int valid=0;
int len=INT_MAX;
int start=0;
while(right<s.size())
{
char c=s[right];
right++;
if(need.count(c))
{
window[c]++;
if(window[c]==need[c])
{
valid++;
}
}
while(valid==need.size())
{
//缩小左边窗口
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);
}
};
2.
class Solution {
public:
bool checkInclusion(string s1, string s2) {
unordered_map<char,int> need,window;
int left=0;
int right=0;
int valid=0;
for(char c:s1) need[c]++;
while(right<s2.size())
{
char c=s2[right];
right++;
if(need.count(c))
{
window[c]++;
if(window[c]==need[c])
{
valid++;
}
}
while(right-left>=s1.size())
{
if(valid==need.size())
{
return true;
}
char d=s2[left];
left++;
if(need.count(d))
{
if(window[d]==need[d])
{
valid--;
}
window[d]--;
}
}
}
return false;
}
};
3.
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
unordered_map<char,int> need,window;
vector<int> res;
for(char c:p) need[c]++;
int left=0;
int right=0;
int valid=0;
while(right<s.size())
{
char c=s[right];
right++;
if(need.count(c))
{
window[c]++;
if(window[c]==need[c])
{
valid++;
}
}
while(right-left>=p.size())
{
if(valid==need.size())
{
res.push_back(left);
}
char d=s[left];
left++;
if(need.count(d))
{
if(window[d]==need[d])
{
valid--;
}
window[d]--;
}
}
}
return res;
}
};
4.
class Solution {
public:
int lengthOfLongestSubstring(string s) {
/* 1.官方题解
if(s.length()==0) return 0;
if(s.length()==1) return 1;
unordered_set<char> lookup;//set容器装连续的不重复子串
int left=0;
int maxstr=0;//关键所在,记录一个最长的长度,往后滑;
for(int i=0;i<s.length();i++)
{
while(lookup.find(s[i])!=lookup.end())//如果在lookup中找到了s[i]就把第一个元素
{
lookup.erase(s[left]);
left++;
}
maxstr=max(maxstr,i-left+1);
lookup.insert(s[i]);
}
return maxstr;*/
// 2.自己的解法
unordered_map<char,int> window;
int left=0;
int right=0;
int res=0;
while(right<s.size())
{
char c=s[right];
right++;
window[c]++;
while(window[c]>1)
{
char d=s[left];
left++;
window[d]--;
}
res=max(res,right-left);
}
return res;
}
};