给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。并返回滑动窗口中的最大值。
![img](https://img-blog.csdnimg.cn/img_convert/9f3449ecdc15b0460717d2b381e6117b.png)
思路
-
当d的长度大于k时,自动抛弃队头元素
-
使用单调队列存储元素,每遍历一个元素
nums[i]
,就把他和队列里面存的元素d[j]
,从末到尾依次比较,如果nums[i] > d[j]
,则把d[j]
丢掉,继续和下一个队列元素比较,反之则直接从后面插入该元素 -
当遍历到第k个元素开始,每次遍历都输出队头元素
-
使用
deque<int> d
存储元素的下标,而不是它的值。因为上面我们使用了单调队列,会遇到一个问题,如nums = [1,3,1,2,0,5],k = 3
,假设d储存的是元素的值:当遍历到0时,由于(1),d里面存的是3、2,然后加入0,得到[3,2,0],d的长度等于k,故不用抛弃3,由于(3),我们应该输出3。
但结果真的这样吗?根据题目要求,窗口长度为3,当遍历到0时,窗口包含的元素为[1,2,0],如图:
实际上,正确结果应该输出2
因此,储存下标的好处,就是能判断队头元素是不是超出窗口范围了,从而抛弃队头元素。不然,就留在队列中,由于它是最大的,会一直输出它
代码
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int> d;
vector<int> res;
int len;
int count;
for(int i =0;i<nums.size();i++)
{
len = d.size();
count = len-1;
// 当d的长度大于k时,自动抛弃队头元素
if(i == d.front()+k)
{
d.pop_front();
count--;
}
// 依次比较,获得单调队列
while(count >= 0 && nums[d[count]] < nums[i]) // d[count]是元素的下标,nums[d[count]]是元素值
{
d.pop_back();
count--;
}
d.push_back(i);
// 输出队头元素
if(i>=k-1)
{
res.push_back(nums[d.front()]);
}
}
return res;
}
};