算法框架
特点:i和j不会回退,区间向前交替扩大和收缩,就像一条向前慢慢蠕动的毛毛虫(bushi)
void slidingWindow(string s) {
unordered_map<char, int> window;
int left = 0, right = 0;
while (right < s.size()) {
// c 是将移入窗口的字符
char c = s[right];
window.add(c)
// 增大窗口
right++;
// 具体分析
printf("window: [%d, %d)\n", left, right);
// 判断左侧窗口是否要收缩
while (left < right && window needs shrink) {
// d 是将移出窗口的字符
char d = s[left];
window.remove(d)
// 缩小窗口
left++;
// 具体分析
}
}
}
代码细节
debug时候主要是要回答三个问题
1、什么时候应该扩大窗口?
2、什么时候应该缩小窗口?
3、什么时候应该更新答案?
例题
最小覆盖子串
题面:返回 s 中涵盖 t 所有字符的最小子串
题解:暴力法:遍历所有子串,寻找最小的包含所有t中元素的子串
滑动窗口算法的思路是这样:
1、初始化 left = right = 0,把左闭右开区间 [left, right) 称为一个「窗口」。
使得一开始区间两个端点重合并且区间不包含任何元素
2、先增加 right 指针扩大窗口 ,直到窗口中的字符串包含了 T 中的所有字符。
3、停止 right,增加 left 指针缩小窗口 ,直到窗口中的字符串不再符合要求。每次增加 left,我们都要更新一轮结果。
4、重复第 2 和第 3 步,直到 right 到达字符串 S 的尽头。
string minWindow(string s, string t) {
unordered_map<char, int> need, window;
for (char c : t) need[c]++;//t中含有的字符
int left = 0, right = 0;
int valid = 0;
int start = 0, len = INT_MAX;
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;
}
// d 是将移出窗口的字符
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);
}
1651




被折叠的 条评论
为什么被折叠?



