(数组_单调队列)滑动窗口的最大值

剑指 Offer 59 - I. 滑动窗口的最大值

难度简单113

给定一个数组 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

解题思路

学习了 @代码随想录 大佬的解法,我来梳理一下我的理解

**建议用一个数组模拟一遍流程更容易理解到这种单调队列的思想。**

 

我们定义一个单调队列(单调递增或单调递减的,这里用到的是单调递增),它的用处就是每次队首就是最大值,即我们滑动一次窗口返回队首即为最大值。

那么这个怎么实现呢?

 

它的结构应该是这样的:

``` cpp

class Myqueue{

public:

    deque<int> que;

    void push(int value)    {

     

    }

    void pop(int value){



    }

    int front(){

        return que.front();

    }

};

```

- push规则:

就是我们每次放入元素value,都要进行这样的操作:如果que不为空并且value > que.back(),就是大于队尾元素,就将队尾元素弹出que.pop_back();直到不满足上述两个条件,才把当前元素放入队列,这其实就是在push每个元素的时候进行了比较,保证元素是递减的。

- pop规则:

由push规则我们知道,que队列中可能并没有完整的nums数组中的所有元素,那么当滑动窗口移动时,怎么模拟pop出K个元素中的第一个呢(value对应代码中的nums[j - k])?它是这样的:如果pop的值value == que.front(),就进行pop。其他值不进行操作,因为不影响,在que中也不一定还存在。主要是如果窗口中要移除的那个元素就算是最大值,也一样得移除,所以pop的时候要进行判断。这是比较难理解的一个点。

- front规则:

直接返回的就是最大值。

 

其他见代码,结合代码看起来更好理解一些。这种写法时间复杂度O(N),但是beats率却不如我之前写的暴力法,我看了一下18个测试用例,如果多一些可能优势就体现出来了。

其他:巩固了deque用法,如:

1. 定义:deque<int> que

2. API:队首front()、队尾back()、弹出队首pop_front()、弹出队尾pop_back()

3. push_back(),放进队尾

 

我又想起常用的queue的一些用法:

1. 定义:queue<int> que

2. API:队首front()、队尾top()

3. push,直接就放进队尾

 代码

```cpp
class Solution {
public:
class Myqueue{
public:
    deque<int> que;
    void push(int value)    {
        while(!que.empty() && value > que.back()){
            que.pop_back();
        }
        que.push_back(value);
    }
    void pop(int value){
            if(!que.empty() && value == que.front()){
                que.pop_front();
            }
        }
    int front(){
        return que.front();
    }
};

    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
       Myqueue my_queue;
       vector<int> result;
       if(nums.size() == 0) return result;
       for(int i = 0; i < k; i++){
           my_queue.push(nums[i]);
       }
       result.push_back(my_queue.front());
       //开始移动滑动窗口
       for(int j = k; j < nums.size(); j++ )
       {
           my_queue.pop(nums[j - k]);
           my_queue.push(nums[j]);
           result.push_back(my_queue.front());
       }
       return result;
    }
};
```

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jasscical

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值