滑动窗口与单调队列
滑动窗口
滑动窗口的窗口就是一个区间,滑动窗口就是遍历每一个区间。

实际就是求定长区间和,这是滑动窗口最简单的题目,只需要实现窗口移动即可
class Solution {
public:
double findMaxAverage(vector<int>& nums, int k) {
double sum = 0;
int n =nums.size();
for(int i = 0;i < k;++i){
sum +=nums[i];
}
double ans = sum;
for(int i = k;i < n;++i){
sum -=nums[i - k];
sum +=nums[i];
ans = max(ans,sum);
}
return ans / k;
}
};
变长窗口
窗口不一定是定长的,滑动窗口也可以用于求最长连续区间
给定一个二进制数组 nums 和一个整数 k,假设最多可以翻转 k 个 0 ,求操作后 数组中连续 1 的最大个数 。
实际是就是找一个区间,区间内有不多于k个0,找最长区间。
class Solution {
public:
int longestOnes(vector<int>& nums, int k) {
int ans = 0,l = 0,n = nums.size(),s0 = 0;
for(int i = 0;i < n;++i){
if(nums[i] == 0){++s0;}
while(s0 > k){
if(nums[l] == 0){
--s0;
}
++l;
}
ans = max(ans,i - l + 1);
}
return ans;
}
};
以上类型的滑动窗口所求最值都是只关注入出窗口的,不需要考虑窗口内部性质,如果要求窗口内的最值,就需要用到单调队列。
双端队列 deque :deque 支持在队头和队尾高效地进行插入和删除操作,非常适合实现单调队列。
借助双端队列存储数据,兼顾「双端 O (1) 操作」和「随机访问 O (1)」。
单调队列:
单调队列是一种特殊的队列数据结构,队列中的元素始终保持单调递增或单调递减的特性。它主要用于高效解决一些区间最值问题,特别是在滑动窗口场景下,能够将原本需要O(nk) ( n为数组长度, k为窗口大小)的时间复杂度优化到O(n) 。
窗口内最值
求窗口最值就是裸单调队列。
- 确保队首为当前最值
- 队首后面单调,队首后为次最值
- 新元素入队如果能比较过队尾,弹出队尾来维护单调(被弹出元素早于新元素离开窗口,后续也用不到被弹元素了)
- 队首离开窗口时出队
为了方便出队一般队列都存储索引
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int> q;
vector<int> ans;
for(int i = 0;i < nums.size();++i){
while(!q.empty() && nums[q.back()] <= nums[i]){
q.pop_back();
}
q.push_back(i);
if(q.front() < i - k + 1){q.pop_front();}
if(i >= k - 1){ans.push_back(nums[q.front()]);}
}
return ans;
}
};

浙公网安备 33010602011771号