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

算法笔记:单调队列

单调队列:

队列元素之间的关系具有单调性(从队首到队尾单调递增/递减),队首和队尾都可以进行入队出队(即插入删除)操作,本质是由双端队列deque实现

适用问题

通常解决动态小区间中寻找极值问题。

239. 滑动窗口最大值

思路:

由于需要比较在一个窗口里面的最大值的问题,最暴力的解法就是每次都去遍历窗口中的元素,然后取极大值,但这种情况只要K稍微大一点性能便会很差,而单调队列可以只进行维护最大值的操作,来优化性能。在本题中,关键的就是一个窗口中最大值在下一次移动的留存问题需要注意,比如[4,2,1],k=2,时,首先窗口为[4,2]那么此时单调队列中的元素就为[2.4],4在队首的位置,那么下一次移动窗口成为[2,1]由于4是上一个窗口的最大值,但也是边界元素,下一次移动就会需要剔除,而单调队列恰好可以做到,那么此时4会从队首弹出,那么队列中次大的2就到队首,那么就和新进来的元素1比对来取值。

单调队列是通过双端队列Deque对象来进行操作,即可以进行头尾操作。

流程是当一个队列入队时,从尾部不断弹出元素进行比较,如果元素比队列中的元素大,那么就将队列中的元素弹出,直到存放到不大于队列中的元素的后面,或者最前面。

一个很有意思的描述。

代码:

class Solution {

    public static Deque<Integer> queue=new LinkedList<>();

    public int[] maxSlidingWindow(int[] nums, int k) {
        
         //思路:单调队列
        //java中的API  Deque:双端队列 可以同时进行头尾操作
        //从队头进行出元素  队尾进元素
         Queue<Integer> result=new LinkedList<>(); //存放结果队列   
         
            if(k==1){
                int [] ex=new int[nums.length];
                for(int c=0;c<nums.length;c++){
                    ex[c]=nums[c];
                }
                return ex;
            }
        //先初始化 第一个窗口
        for(int x=0;x<k;x++){
            push(nums[x]); //调用入栈操作
        }
        result.offer(queue.peekFirst());
        pop(nums[0]); //判断左指针是否是最大值下标 不是则不用管

        //开始从第一个窗口后进行判断
         for(int left=1,right=k;right<nums.length;){
               //那么第二个窗口和第一个窗口的区别就是要 判断左指针的元素是否是当前窗口最大值 右指针的元素是否比当前窗口最大值大
               //先判断当前右指针 使右指针元素入队
                push(nums[right]);  
                //右指针入队后 查看队首的最大值
                result.offer(queue.peekFirst()); //将最大值存入结果队列
                //然后需要在移动指针前判断当前左指针是否是最大元素
                pop(nums[left]); //如果是就需要弹出队首元素

                left++; 
                right++;

         }

         Object [] r=new Object[result.size()];
         r=result.toArray();
         int [] R=new int[r.length];
          for(int y=0;y<R.length;y++){
                R[y]=Integer.parseInt(String.valueOf(r[y]));
            }

        queue.clear();
        return R;
    }

    public static void push(int x){ // 入队方法 需要从队尾去判断元素大小
        
        while(!queue.isEmpty()&&queue.peekLast()<x){  //队列首先不能为空 然后从队尾拿元素 如果目标值大于队尾元素 则将队尾元素弹出
            queue.pollLast(); //将所有小于目标值的队尾元素弹出
        }//所有元素已经弹出
        //然后将该元素放置队尾
        queue.offerLast(x);

        //这样做是因为 只需要维护一个滑动窗口中的最大值即可,其余元素不用维护 当滑动窗口变动时 只需要关注最大值的那个元素是否被移除
    }


    public static void pop(int y){
        //出队方法是当滑动窗口左指针移动时 需要判断移出去的那个左边的元素是否是最大值,如果是最大值就需要调用该方法 将单调队列中的最大值弹出
       if(!queue.isEmpty()&&y==queue.peekFirst()){
            queue.pollFirst();//弹出队首元素
       }
    } //出队方法  从队头出队拿元素


}


http://www.kler.cn/a/410140.html

相关文章:

  • 函数类型注释和Union联合类型注释
  • Hive的基础函数-日期函数
  • 【自适应和反应式机器人控制】编程练习 1.1:计算最优轨迹 + 编程练习 1.3:基于三阶多项式的闭式时变轨迹发生器
  • 浏览器缓存与协商缓存
  • Java项目实战II基于微信小程序的图书馆自习室座位预约平台(开发文档+数据库+源码)
  • SAP开发语言ABAP常见面试问题及答案
  • 如何在树莓派5+ubunut24上编译Qt5.15.15
  • 文件上传代码分析
  • C++数据结构与算法
  • 干货分享|分布式数据科学工具 Xorbits 的使用
  • k8s中部署filebeat进行日志监听并发送到es中
  • 门控循环单元(GRU)与时间序列预测应用
  • spring boot jpa中 Hibernate 注解 @Immutable 的使用场景
  • 二叉树oj题解析
  • jQuery-Word-Export 使用记录及完整修正文件下载 jquery.wordexport.js
  • 系统设计时应时刻考虑设计模式基础原则
  • flutter 专题十一 Fair原理篇Fair逻辑动态化架构设计与实现
  • 永磁同步电机末端振动抑制(输入整形)
  • 【Electron学习笔记(二)】基于Electron开发应用程序
  • 怎么规划一套电话机器人系统?
  • GitLab/GitHub 多环境配置SSH密钥
  • KADB支持arm架构Pro*c
  • 开源客户关系管理平台EspoCRM
  • 001 MATLAB介绍
  • 【Spring Cloud】 Gateway配置说明示例
  • GitHub 和 GitLab