算法-栈和队列篇04-滑动窗口最大值

news/2025/2/23 22:23:34

滑动窗口最大值

力扣题目链接

题目描述

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

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

解题思路

这道题目一开始我是直接使用滑动窗口去做的, 在过程中使用一个pair来记录当前窗口内最大的数及其位置。但是该方法的时间复杂度是O(n)-O(nm),有一个比较大的测试用例会超时,所以借鉴了一下他人的解法。

滑动窗口解法(超时)

定义一个ans数组用于保存答案,一个pair保存当前窗口的最大值及其位置;
先遍历数组前k个,并记录下最大数nums[i]和i;
然后遍历后面的数据,并遵循以下规则:

  • 当下一个数据大于窗口最大数据,直接修改pair;
  • 当最大数据在窗口头部即将出去时,重新寻找最大值;
    把最大值存在ans中。

优先队列(正解)

定义一个ans数组和双端队列dq;
直接遍历数组,并遵循以下规则:

  • 当下一个数据大于等于当前队列中队尾的数据时,把队尾数据弹出,并继续这个过程直到队列为空或者队尾数据大于下一个数据;
  • 把队列头部的数据放入ans中;
  • 当头部数据的下标比i小k时,说明该数据已经出了窗口范围,将其从头部弹出;
    返回ans即可。

题解

滑动窗口解法(超时)

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> ans;
        vector<int> mpair = {0, nums[0]};

        for(int i = 1; i < k; i++){
            if(nums[i] > mpair[1]){
                mpair = {i, nums[i]};
            }
        }
        ans.push_back(mpair[1]);

        for(int i = 0; i < nums.size() - k; i++){
            if(nums[i + k] > mpair[1]){
                //窗口尾部加入元素大于原窗口最大元素,直接替换
                mpair = {i + k, nums[i + k]};
            }
            else if(mpair[0] == i){
                //原窗口最大元素在头部,即将出窗口,重新寻找最大值
                mpair = {i + 1, nums[i + 1]};
                for(int j = 2; j <= k; j++){
                    if(nums[i + j] > mpair[1]){
                        mpair = {i + j, nums[i + j]};
                    }
                }
            }
            ans.push_back(mpair[1]);
        }

        return ans;
    }
};

优先队列(正解)

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        deque<int> dq;
        vector<int> ans;

        for(int i = 0; i < nums.size(); i++){
            while(!dq.empty() && nums[dq.back()] <= nums[i]){
                dq.pop_back();
            }
            dq.push_back(i);
            if(i - dq.front() >= k){
                dq.pop_front();
            }
            if(i >= k - 1){
                ans.push_back(nums[dq.front()]);
            }
        }

        return ans;
    }
};

总结

这道题目还是很有难度的,因为数据给的非常苛刻;
也是让我见到了双端队列更加灵活的用法,一开始有想到用优先队列,但是在存储数据上,有一个没法判断说明时候数据出窗口,所以没采用;这里通过存储下标i,然后比较大小和读取数据的时候再访问nums数组,这种方法去实现优先队列就比较难以想到。


http://www.niftyadmin.cn/n/5863822.html

相关文章

Orcale、MySQL中参数类型的详解和运用场景(带示例)

Oracle 中的参数类型及运用场景 1. 数值类型 NUMBER(p, s) 详解&#xff1a;p 表示精度&#xff08;即数字的总位数&#xff09;&#xff0c;s 表示小数位数。例如&#xff0c;NUMBER(5, 2) 可以存储最大为 999.99 的数字。运用场景&#xff1a;适用于需要精确计算的财务数据…

docker基操

docker基操 首先就是安装docker使用docker:创建容器-制作一个镜像-加载镜像首先就是安装docker 随便找一个教程安装就可以,安装过程中主要是不能访问谷歌,下面这篇文章写了镜像的一些问题: 安装docker的网络问题 使用docker:创建容器-制作一个镜像-加载镜像 主要是参考:这篇…

【数字图像处理二】图像增强与空域处理

1. 图像增强的目的 图像增强的目的是通过各种处理方法改善图像的视觉效果&#xff0c;旨在满足特定应用场合的需求。其核心目的是增强图像的整体或局部特性。通过图像增强&#xff0c;我们能够将原本模糊的图像变得更加清晰&#xff0c;突出某些感兴趣的特征&#xff0c;扩大图…

一个解析cyber record文件的python示例脚本

Cyber RT 是百度开源的一个高性能、灵活的机器人操作系统&#xff0c;cyber record 是 Cyber RT 中用于录制和回放数据的工具。下面是一个使用 Python 解析 cyber record 文件的示例&#xff0c;该示例使用 cyber_py 库&#xff08;Cyber RT 的 Python 绑定&#xff09;来读取记…

迎接2025,立个flag

2025计划书 博客更新时间 每周二、周四、周天晚上20&#xff1a;00-23:00间进行更新 博客内容粗略版规划 1、 大模型相关论文分享&#xff08;数据标注、COT、prompt等方向&#xff09; 2、强化学习数学理论&#xff08;内容偏数学&#xff0c;故周天晚上更新&#xff09; 3、…

Python常见面试题的详解17

1. 说明HTTP 和 HTTPS的区别 安全性&#xff1a;HTTP 是明文传输协议&#xff0c;这意味着在数据传输过程中&#xff0c;信息就像在 “裸奔”&#xff0c;容易被窃取和篡改&#xff0c;安全性堪忧。而 HTTPS 是在 HTTP 基础上加入了 SSL/TLS 协议&#xff0c;通过加密和身份验证…

Java 虚拟机(JVM)方法区详解

文章目录 Java 虚拟机&#xff08;JVM&#xff09;方法区详解1. 什么是方法区&#xff1f;2. 方法区的作用3. 方法区的存储内容3.1 类的元数据&#xff08;Class Metadata&#xff09;3.2 运行时常量池&#xff08;Runtime Constant Pool&#xff09;3.3 静态变量&#xff08;S…

Python 数据结构与实践深度剖析

Python 数据结构与实践深度剖析 本文旨在深入剖析 Python 数据结构及其在实际编程中的应用。通过详细的理论阐述、丰富的代码示例以及直观的图表&#xff0c;帮助读者全面掌握 Python 数据结构的核心概念与操作技巧&#xff0c;助力读者在编程实践中灵活运用数据结构解决各类问…