算法题(182):滑动窗口
审题:
本题需要我们找到长度为n的窗口从左到右滑动到所有位置的窗口内最大值与最小值并输出
思路:
方法一:单调双端队列
我们创建一个双端队列并按照以下规则进行操作即可筛选出每一个窗口的最大值/最小值
a数组:记录初始数据的数组
以查找最大值为例:
1.当a[i]>=a[q.back()]:将队列尾部索引数据弹出
2.当a[i]<a[q.back()]:将当前索引插入队列
3.当队头数据已经不在当前窗口内时:弹出队头索引数据
4.当i>=k:输出队头索引数据对应a数组的数据值
疑问:
操作1:因为当前遍历到的数据已经比队尾数据的值要大,所以该队尾数据不可能是后续窗口的最大值,直接弹出即可。
若两者相等,也是弹出,因为后续遍历过程会把先出现的数据淘汰掉
操作2:因为后续计算队头是否还在窗口内需要用到索引,所以我们不存储数据值,而是存储他在a数组的索引
操作3:通过队头和队尾的差值来计算
操作4:需要保证窗口完整出现后才输出
解题:
#include<iostream> #include<deque> using namespace std; const int N = 1e6 + 10; int n, k; int a[N]; int main() {cin >> n >> k;for (int i = 1; i <= n; i++) cin >> a[i];//查找最小值deque<int> q;for (int i = 1; i <= n; i++){while (q.size() && a[i] <= a[q.back()]) q.pop_back();q.push_back(i);if (q.back() - q.front()+1 > k) q.pop_front();if (i >= k) cout << a[q.front()] << " ";}//查找最大值cout << endl;while (q.size()) q.pop_back();for (int i = 1; i <= n; i++){while (q.size() && a[i] >= a[q.back()]) q.pop_back();q.push_back(i);if (q.back() - q.front() +1 > k) q.pop_front();if (i >= k) cout << a[q.front()] << " ";}return 0; }
注意:
1.在调用队列的back等函数前需要确保队列不为空,所以在不确定数据量的使用前需要加一个q.size()的判断
2.最后输出的是数据值本身,所以需要用a[q.front()]