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月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
1月前
【LeetCode 26】239.滑动窗口最大值
【LeetCode 26】239.滑动窗口最大值
32 1
|
3月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
57 6
|
3月前
|
Python
【Leetcode刷题Python】剑指 Offer 26. 树的子结构
这篇文章提供了解决LeetCode上"剑指Offer 26. 树的子结构"问题的Python代码实现和解析,判断一棵树B是否是另一棵树A的子结构。
52 4
|
3月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
118 2
|
25天前
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
20 1
|
2月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
1月前
【LeetCode 04】滑动窗口法总结
【LeetCode 04】滑动窗口法总结
19 0
|
3月前
|
索引 Python
【Leetcode刷题Python】从列表list中创建一颗二叉树
本文介绍了如何使用Python递归函数从列表中创建二叉树,其中每个节点的左右子节点索引分别是当前节点索引的2倍加1和2倍加2。
61 7
|
3月前
|
Python
【Leetcode刷题Python】剑指 Offer 22. 链表中倒数第k个节点
Leetcode题目"剑指 Offer 22. 链表中倒数第k个节点"的Python解决方案,使用双指针法找到并返回链表中倒数第k个节点。
54 5