当前位置: 首页 > article >正文

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

滑动窗口最大值

力扣题目链接

题目描述

给你一个整数数组 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.kler.cn/a/557806.html

相关文章:

  • 深入理解 lua_KFunction 和 lua_CFunction
  • cocos2dx Win10环境搭建(VS2019)
  • 2.1作业
  • 25轻化工程研究生复试面试问题汇总 轻化工程专业知识问题很全! 轻化工程复试全流程攻略 轻化工程考研复试真题汇总
  • linux常用基础命令_最新版
  • Embedding模型
  • excel中VBA宏的使用方法?
  • nginx 反向代理 配置请求路由
  • uniapp封装请求
  • 在线办公小程序(springboot论文源码调试讲解)
  • 伦敦金库彻底断供的连锁反应推演(截至2025年02月22日)
  • BFS算法解决最短路径问题(典型算法思想)—— OJ例题算法解析思路
  • 深入理解设计模式之策略模式
  • JDBC连接保姆级教程
  • Redis数据结构总结-quickList
  • 漏扫问题-服务器中间件版本信息泄露(消除/隐藏Nginx版本号)
  • 一文说清楚Java中的volatile修饰符
  • 图解JVM-1. JVM与Java体系结构
  • 提升 AI 服务的稳定性:Higress AI 网关的降级功能介绍
  • JavaScript异步编程方式多,区别是什么?