后面的例题全都是直接套用这个模板,熟记并理解这个模板就行了
string minWindow(string s, string t) {//寻找s中涵盖的t
unordered_map<char, int>need, window;//初始化两个哈希表,记录窗口中的字符和需要凑齐的字符,needhe window相当于计数器,分别记录t中字符出现的次数和窗口中相应字符出现的次数
for(char c : t) need[c]++;//map[key]访问key值,如果key不存在,C++会自动创建这个key,并把map[key]赋值为0
int left = 0, right = 0;//窗口左开右闭,初始情况下窗口没有包含任何元素
int valid = 0;//表示窗口中满足need条件的字符个数,如果valid=need.size(),则说明窗口已满足条件,已经完全覆盖了串T
while(right < s.size()){
char c = s[right];//c是将移入窗口的字符
right++;//右移窗口
//...进行窗口内数据的一系列更新
printf("window:[%d,%d)\n", left, right);//debug输出位置
while(window needs shrink){//判断左侧窗口是否要收缩
char d = s[left];//d是将移出窗口的字符
left++;//左移窗口
//...进行窗口内数据的一系列更新
}
}
}
class Solution {
public:
string minWindow(string s, string t) {//寻找s中涵盖的t
//滑动窗口
unordered_map<char, int>need, window;//初始化两个哈希表,记录窗口中的字符和需要凑齐的字符,needhe window相当于计数器,分别记录t中字符出现的次数和窗口中相应字符出现的次数
for(char c : t) need[c]++;//map[key]访问key值,如果key不存在,C++会自动创建这个key,并把map[key]赋值为0
int left = 0, right = 0;//窗口左开右闭,初始情况下窗口没有包含任何元素
int valid = 0;//表示窗口中满足need条件的字符个数,如果valid=need.size(),则说明窗口已满足条件,已经完全覆盖了串T
int start = 0, len = INT_MAX;//记录最小覆盖字串的起始索引及长度
while(right < s.size()){
char c = s[right];//c是将移入窗口的字符
right++;//右移窗口
//...进行窗口内数据的一系列更新
if(need.count(c)){//map_name.count()的结果只能为0和1,可以以此来判断键值元素是否存在,存在则为1
window[c]++;//窗口中相应字符出现的次数
if(window[c] == need[c])//窗口与t串中的对应字符出现的次数相同
valid++;
}
//printf("window:[%d,%d)\n", left, right);//debug输出位置
while(valid == need.size()){//判断左侧窗口是否要收缩
if(right-left < len){//在这里更新最小覆盖子串
start = left;//索引位置
len = right - left;//覆盖子串的大小
}
char d = s[left];//d是将移出窗口的字符
left++;//左移窗口
//...进行窗口内数据的一系列更新
if(need.count(d)){
if(window[d] == need[d])//窗口中d字符出现的次数=t串中d出现的次数
valid--;//value:满足need条件字符的个数,因为窗口左移了,所以value要--,方便后续更新len
window[d]--;//窗口中d出现的次数-1
}
}
}
return len == INT_MAX ? "" : s.substr(start, len);
//形式 : s.substr(pos, len)
//返回值: string,包含s中从pos开始的len个字符的拷贝(pos的默认值是0,len的默认值是s.size() - pos,即不加参数会默认拷贝整个s)
}
};
class Solution {
public:
bool checkInclusion(string s1, string s2) {
unordered_map<char, int>need, window;
for(char c : s1) need[c]++;
int left = 0, right = 0;
int valid = 0;
//窗口右+
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;
}
};
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
unordered_map<char, int>need, window;
for(char c : p) need[c]++;
int left = 0, right = 0;
int valid = 0;
vector<int> res;//记录结果
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()){
//当窗口符合条件时,把起始索引加入res
if(valid == need.size())
res.push_back(left);//push_back()函数的用法:函数将一个新的元素加到vector的最后面,位置为当前最后一个元素的下一个元素
char d = s[left];
left++;
//窗口内数据更新
if(need.count(d)){
if(window[d] == need[d])
valid--;
window[d]--;
}
}
}
return res;
}
};
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char,int>window;
int left = 0, right = 0;
int res;//记录结果
while(right < s.size()){
char c = s[right];
right++;
window[c]++;
//判断窗口左侧是否需要收缩
while(window[c] > 1){//window[1]>1说明窗口内存在重复的字符,不符合条件,窗口左侧需要收缩
char d = s[left];
left++;
window[d]--;
}
res = max(res, right - left);
}
return res;
}
};