题目描述
给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。
示例:
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 的均摊时间复杂度都是O(1)。
若队列为空,pop_front 和 max_value 需要返回 -1
示例 1:
输入:
["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]
[[],[1],[2],[],[],[]]
输出: [null,null,null,2,1,2]
示例 2:
输入:
["MaxQueue","pop_front","max_value"]
[[],[],[]]
输出: [null,-1,-1]
思路
滑动窗口的最大值,无非也是一个固定长度队列,,每一次都取它的最大值,所以滑动窗口的最大值问题可以转化为求队列的最大值问题.
如何保存一个队列的最大值呢?
比如对于2,1,3,4,5,4,4,2,1这样一个队列,它的最大值依次为2,2,3,4,5,5,5,5,5
对于升序序列,1,3,4,5我们实际上需要保存的元素就是5,那么第一个元素'2'需要保存吗?不需要,我们就可以发现,只要出现一个比之前元素大的元素,之前小的元素就都需要pop_back,直到我们遇到'4',它比5小,需要push_back(),因为如果'5'被pop了,那么下一个最大元素就是4,同理4后面的2也需要被push_back,2后面的1也需要被push_back.
我们只需要维持一个非递增的双端队列,每一次push进去新元素时,对于之前存在的小于这个新元素num[i]的元素,我们就pop_back.直到队列为空或者碰到比nums[i]还要大的元素.这样从前到后,我们每一次取大值(前提非空),就return deque.front().但是我们在pop_front()函数里面需要注意--当被pop的front元素和deque.front()元素相等的时候,就需要deque.pop().
具体实现见
代码
#include<queue>
using namespace std;
class MaxQueue {
public:
queue<int> que;
deque<int> deq;
MaxQueue() {
}
int max_value() {
if(!deq.empty())
return deq.front();
else {
return -1;
}
}
void push_back(int value) {
que.push(value);
while (!deq.empty()&&value > deq.back()) {
deq.pop_back();
}
deq.push_back(value);
}
int pop_front() {
if (que.empty()) {
return -1;
}
int temp = que.front();
que.pop();
if (temp == deq.front()) {
deq.pop_front();
}
return temp;
}
};
/**
* Your MaxQueue object will be instantiated and called as such:
* MaxQueue* obj = new MaxQueue();
* int param_1 = obj->max_value();
* obj->push_back(value);
* int param_3 = obj->pop_front();
*/
滑动窗口最大值--思路
如果领悟了上一题那么这一题至少不会没有思路,我们维持一个双端队列,存储当前窗口的最大值,vector.push_back(deuque.front()).然后设置两个指针,left,right,分别指向左边界和右边界,如果右边界>size,那么说明到头了.return res.
我们循环的逻辑就是先deque.pop_back()掉那些<nums[right]的元素,然后deque.push_back(nums[right]),vector.push_back(最大值---deque.front()),同时判断左边移除的元素是不是等于这个最大值,如果同样等于最大值,我们就移除deque.back().
代码
#include<vector>
#include<queue>
using namespace std;
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
if (nums.size() == 0) return {};
deque<int> deq;
int left = 0;
int right = k - 1;
vector<int> res;
deq.push_back(nums[0]);
for (int i = 1; i < k; ++i) {
while (!deq.empty()&&nums[i] > deq.back()) {
deq.pop_back();
}
deq.push_back(nums[i]);
}
res.push_back(deq.front());
if (deq.front() == nums[left]) deq.pop_front();
++left, ++right;
while (right < nums.size()) {
while (!deq.empty()&&nums[right] > deq.back()) {
deq.pop_back();
}
deq.push_back(nums[right]);
res.push_back(deq.front());
if (nums[left] == deq.front()) deq.pop_front();
++left, ++right;
}
return res;
}
};