leetcode239滑动窗口的最大值刷题打卡

简介: leetcode239滑动窗口的最大值刷题打卡

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

返回 滑动窗口中的最大值

示例 1:

输入: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

示例 2:

输入:nums = [1], k = 1
输出:[1]

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • 1 <= k <= nums.length

题解思路

本题一开始直接想到的思路就是将nums分块,每个块各自排序然后找到最大值然后push_back到结果数组里面。思路是对的 但是太暴力了,超时是必然的,于是我从carl那里了解到可以用单调队列来解此题

  • 单调队列
  • 此队列中的元素保持单调性,push进元素只能是比队列中已有元素大或者小,如果不满足,则会抹去队列中不满足的元素,知道可以push为止,这样就保持了队列的单调性
  • 例如:假设有一个单调队列,里面的元素是单调递减的,意思就是front永远是最大的,假设有一个数组[1, 3, -1, -3, 5, 3, 6, 7],依次将里面的元素push_back进单调队列,队列元素的变化情况是
    [1] 首先push第一个元素
    [3] push第二个元素的时候就要开始维护了,1<3,则抹去1,push 3 使第一元素保持最大
    [3,-1] 3>-1,直接push,不需要维护
    [3,-1,-3] -1>-3,直接push,不需要维护
    [5] any[3,-1,-3]<5 ,则直接抹去队列中全部元素然后push 5
    [5,3] 5>3,直接push,不需要维护
    [6] any[5,3]<6,则抹去队列中全部元素然后push 5
    [7] 6<7,则抹去6,push 7
  • 可以看出,单调队列中的元素一直保持着单调性,这就是单调队列

此题是找滑动窗口中的最大值,故单调递减队列可以满足(队头最大),滑动窗口的capacity为k,push操作很好理解和实现,这道题的关键是什么时候pop出第一元素,要保证窗口里面的元素都是窗口里面的元素(这句话看似是废话其实就是解题的关键,就是如果该窗口向后移动了,则必须pop掉不属于该窗口的值,有一种情况需要处理就是当窗口在这里时[ 1 [ 3 1 2 ] 0 5 ],此时单调队列中的元素为[3, 2],之后就是push 0 ,如何保证在capacity没满的情况下push 0且pop 3 是最关键的点),需要特殊设计pop函数,pop会传进一个value值,判断传进来的value值是否等于单调队列的队头值,该判断的意义是,需要结合调用该代码的部分进行说明

部分代码:

class my_que{
public:
...   
        void pop_deque(int value){
            if(value == get_front()){
                d.pop_front();
            }
        } 
        int get_front(){ return d.front();}
vector<int> maxSlidingWindow(vector<int>& nums, int k) {  //假设nums:[1,3,1,2,0,5];k:3
... 
my_que temp;   
...
for(int i = k;i < nums.size();i++){
            temp.pop_deque(nums[i-k]);  //理解这一行代码的意义
            temp.push_deque(nums[i]);
            result.push_back(temp.get_front());
        }
...

nums[i-k] i-k的取值为 0,1,2,为0的意思是即将要push索引为3的值(2)了,在pop_deque函数中,会判断nums[0]是否等于get_front(),该判断的意义是查看索引为0的1值是否是初始滑动窗口的头值,如果是则会pop,这样就保证了窗口里面的元素都是窗口里面的元素。

难点已经解决,接下来是该程序的大致思路流程:

建立一个自己的单调队列,内部用deque实现,push的实现

//根据单调递减队列的原理所设计
void push_deque(int value){
        while(!d.empty() && d.back() < value)
            d.pop_back();
        d.push_back(value);
    }

单调队列整体类代码展示

class my_que{
private:
    deque<int> d;
public:
    my_que() = default;
    void push_deque(int value){
        while(!d.empty() && d.back() < value)
            d.pop_back();
        d.push_back(value);
    }
    void pop_deque(int value){
        if(value == get_front()){
            d.pop_front();
        }
    } 
    int get_front(){
        int result = d.front();
        return result;
    }
};

单调队列设计好之后,接下来就是窗口滑动模拟,以nums:[1,3,1,2,0,5];k:3来模拟,首先将nums的前k个元素push进单调队列,然后直接将第一元素push进result数组,接着开始移动窗口

完整代码:

class Solution {
public:
    class my_que{
    private:
        deque<int> d;
    public:
        void push_deque(int value){
            while(!d.empty() && d.back() < value) //如果不满足单调则从后向前逐个抹掉元素
                d.pop_back();
            d.push_back(value);
        }
        void pop_deque(int value){
            if(value == get_front()){
                d.pop_front();
            }
        } 
        int get_front(){
            int result = d.front();
            return result;
        }
    };
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        my_que temp;
        for(int i = 0;i < k;i++){
            temp.push_deque(nums[i]);
        }
        vector<int> result;
        result.push_back(temp.get_front());
        //开始滑动窗口
        for(int i = k;i < nums.size();i++){
            temp.pop_deque(nums[i-k]);
            temp.push_deque(nums[i]);
            result.push_back(temp.get_front());
        }
        return result;
    }
};


相关文章
|
2月前
|
机器学习/深度学习 算法
力扣刷题日常(一)
力扣刷题日常(一)
20 2
|
2月前
|
存储 索引
《LeetCode》—— LeetCode刷题日记
《LeetCode》—— LeetCode刷题日记
|
2月前
|
搜索推荐
《LeetCode》——LeetCode刷题日记3
《LeetCode》——LeetCode刷题日记3
|
2月前
|
容器
《LeetCode》——LeetCode刷题日记1
《LeetCode》——LeetCode刷题日记1
|
2月前
|
算法
LeetCode刷题---21.合并两个有序链表(双指针)
LeetCode刷题---21.合并两个有序链表(双指针)
|
2月前
|
算法
LeetCode刷题---19. 删除链表的倒数第 N 个结点(双指针-快慢指针)
LeetCode刷题---19. 删除链表的倒数第 N 个结点(双指针-快慢指针)
|
2月前
|
算法 测试技术
LeetCode刷题--- 430. 扁平化多级双向链表(深度优先搜索)
LeetCode刷题--- 430. 扁平化多级双向链表(深度优先搜索)
|
2月前
|
存储
实现单链表的基本操作(力扣、牛客刷题的基础&笔试题常客)
实现单链表的基本操作(力扣、牛客刷题的基础&笔试题常客)
144 38
|
10天前
刷题之Leetcode160题(超级详细)
刷题之Leetcode160题(超级详细)
11 0
|
10天前
刷题之Leetcode206题(超级详细)
刷题之Leetcode206题(超级详细)
21 0
刷题之Leetcode206题(超级详细)

热门文章

最新文章