滑动窗口大致思路
1.我们使用双指针的思路,初始定义两个指针,left=right=0,把索引闭区间[left,right]看作一个滑动窗口
2.然后不断增加right的值,直到窗口中的字符串符合要求
3.然后,停止增加right的值,转而增加left的值,直到窗口中的字符串不符合要求,每次增加left,就要更新一轮结果。
4.不断重复2,3步骤,直到遍历完整个字符串
通俗来讲,第2步是为了找到可行解,然后第三步是为了“优化可行解”。
滑动窗口的窗口大小可能固定,也可能不固定。
窗口大小固定代码模板:
// 固定窗口大小为 k
string s;
// 在 s 中寻找窗口大小为 k 时的所包含最大元音字母个数
int right = 0;
while(right < s.size()) {
window.add(s[right]);
right++;
// 如果符合要求,说明窗口构造完成,
if (right>=k) {
// 这是已经是一个窗口了,根据条件做一些事情
// ... 可以计算窗口最大值等
// 最后不要忘记把 right -k 位置元素从窗口里面移除
}
}
return res;
窗口大小不固定代码模板:
string s, t;
// 在 s 中寻找 t 的「最小覆盖子串」
int left = 0, right = 0;
string res = s;
while(right < s.size()) {
window.add(s[right]);
right++;
// 如果符合要求,说明窗口构造完成,移动 left 缩小窗口
while (window 符合要求) {
// 如果这个窗口的子串更短,则更新 res
res = minLen(res, window);
window.remove(s[left]);
left++;
}
}
return res;
例题:
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_set<char>res;
int n = s.length();
int rk=-1,ans=0;
for(int i=0;i<n;i++){
if(i!=0){
res.erase(s[i-1]);
}
while(rk+1<n && ! res.count(s[rk+1])){
rk++;
res.insert(s[rk]);
}
ans=max(ans,rk-i+1);
}
return ans;
}
};
给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
vector<int>ans;
if(s.length() == 0 || words.size() == 0) return ans;
int n = s.length();//字符串长度
int len = words[0].length();//一个单词的长度
int count = words.size();//单词个数
int sum_len = count*len;//单词总长度
unordered_map<string,int>mp; //统计每个单词出现的次数
for(int i=0;i<words.size();i++){
mp[words[i]]++;
}
for(int i=0;i<len;i++){
int left=i,right=i;
unordered_map<string,int>tmap;
int cnt = 0;
while(right+len<=n){ //截取是从right开始,故是小于等于
string tmp = s.substr(right,len);
right+=len;
if(mp.count(tmp)==0){ //若该单词未出现过
cnt=0;
left = right;
tmap.clear();
}
else { //单词出现过
tmap[tmp]++;
cnt++;
while(tmap[tmp]>mp[tmp]){ //重点部分,若该单词次数超了,说明在(left->right-len)之间一定有个字符串和tmp相等,因此从left开始截取字符串,舍掉超出的那部分
string t=s.substr(left,len);
tmap[t]--;
cnt--;
left+=len;
}
if(cnt == count) ans.push_back(left);
}
}
}
return ans;
}
};