题目:
给定一个数组和滑动窗口的大小,请找出所有滑动窗口里的最大值。
输入
2 3 4 2 6 2 5 1
输出
4 4 6 6 6 5
题解:
在存入一个数字之前,首先要判断队列里已有数字是否小于待存入的数字。
1. 如果已有数字不大于待存入的数字,这些数字已不可能是滑动窗口的最大值,依次它们将会依次从队列的尾部删除,然后存入待存入的值;
2. 如果已有数字大于待存入的数字,那么当已有数字滑出窗口后,待存入的数字还是有可能成为滑动窗口的最大值,所以也应该存入待存入的值。
同时,如果队列头部的数字已经从窗口里滑出,滑出的数字也需要从队列的头部删除。也就是说,无论什么情况,待存入的值都应该存入队列,只是需要判断是否删除队列的头尾元素。由于队列的头部和尾部都有可能删除数字,那么我们就需要两端开口的序列即双端序列deque。
还有一个问题就是如何知道滑动窗口是否还包括队列的头部数值,即如何知道滑动窗口是否包括一个数字,应该在队列里存入数字的在数组中的下标,而不是数值。当一个数字的下标与当前处理的数字的下标之差大于或等于滑动窗口的大小时,这个数字已经从窗口滑出,可以从队列中删除了。
Solution 1
#include <iostream> #include <deque> #include <vector> using namespace std; vector<int> windowMaxOfArray(vector<int> &nums, int width) { vector<int> maxInWidows; deque<int> q; int n = nums.size(); if (n >= width && n > 0) { for (int i = 0; i < width; ++i) { while (!q.empty() && nums[i] >= nums[q.back()]) q.pop_back(); q.push_back(i); } for (int i = width; i < n; ++i) { maxInWidows.push_back(nums[q.front()]); while (!q.empty() && nums[i] >= nums[q.back()]) q.pop_back(); if (!q.empty() && (i - q.front()) >= width) q.pop_front(); q.push_back(i); } maxInWidows.push_back(nums[q.front()]); } return maxInWidows; } int main() { int n, width; cin >> n; cin >> width; vector<int> nums(n, 0); for (int i = 0; i < n; ++i) { cin >> nums[i]; } vector<int> res = windowMaxOfArray(nums, width); for (auto num : res) { cout << num << " "; } cout << endl; system("pause"); return 0; }