LeetCode239. 滑动窗口最大值

题目

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回滑动窗口中的最大值。

分析

求每个窗口内部的最大值问题,就等同于求连续特定区间内部的最大值最小值问题,这就是单调队列的应用之一。

单调队列用双端队列实现。常用的queue在没有指定容器的条件下,用的底层就是双端队列。注意:单调队列不是并不是优先级队列,保存了所有的元素。它只保留可能成为最大(小)元素。

设计单调(递减)队列的规则:

1. 如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作

2.如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止

上面是代码随想录的Carl大佬总结。

代码

 1 class Solution {
 2 private:
 3 //单调队列,用dequeue实现从大到小
 4 class MyQueue{
 5 public:
 6     deque<int>que;
 7 
 8     //每次需要弹出元素,要与单调队列开头元素比较,如果和开头元素相同,则弹出
 9     //否则,不做任何操作
10     void pop(int x){
11         if(!que.empty() && x == que.front()){
12             que.pop_front(); //从双端队列头部弹出,该元素是最大元素
13         }
14     }
15 
16     //每次需要进入元素,要与单调队列尾部部元素进行比较。
17     //如果要进入元素比单调队列元素的值大,就将单调队列中小于要进入的元素从队列尾部弹出
18     //直到push的值小于等于单调队列元素为止。这样就保持了单调递减的性质
19     void push(int x){
20         while(!que.empty() && x > que.back()){
21             que.pop_back();
22         }
23         que.push_back(x);//从队列尾部加入元素x
24     }
25     int front(){
26         return que.front();
27     }
28 };
29 public:
30     vector<int> maxSlidingWindow(vector<int>& nums, int k) {
31         MyQueue que;
32         vector<int>res;
33         //首先将前k个加入单调队列
34         for(int i = 0;i < k;i++){
35             que.push(nums[i]);
36         }
37         res.push_back(que.front());
38         //开始进行窗口滑动,窗口每向前移动一次,窗口要移除元素,加入元素
39         //并且返回单调队列的头部元素(保存了最大值)加入res
40         for(int i = k;i < nums.size();i++){
41             que.pop(nums[i - k]); //窗口移除元素
42             que.push(nums[i]);//窗口加入元素
43             res.push_back(que.front());
44         }
45         return res;
46 
47     }
48 };

时间复杂度O(n),空间复杂度O(k)

原文地址:https://www.cnblogs.com/fresh-coder/p/14336594.html