单调队列初步「建议收藏」

单调队列初步「建议收藏」
一直弄不明白单调队列是什么,在网上也找不到易懂的介绍。最后结合别人博客上的介绍和程序看才理解是怎么回事。
我们从最简单的问题开始:
给定一个长度为N的整数数列a(i),i=0,1,…,N-1和窗长度k.
要求:
     f(i)=max{a(i-k+1),a(i-k+2),…,a(i)},i=0,1,…,N-1
问题的另一种描述就是用一个长度为k的窗在整数数列上移动,求窗里面所包含的数的最大值。
解法一:

大家好,又见面了,我是你们的朋友全栈君。

一直弄不明白单调队列是什么,在网上也找不到易懂的介绍。最后结合别人博客上的介绍和程序看才理解是怎么回事。

我们从最简单的问题开始:

给定一个长度为N的整数数列a(i),i=0,1,…,N-1和窗长度k.

要求:

      f(i) = max{a(i-k+1),a(i-k+2),…, a(i)},i = 0,1,…,N-1

问题的另一种描述就是用一个长度为k的窗在整数数列上移动,求窗里面所包含的数的最大值。

解法一:

很直观的一种解法,那就是从数列的开头,将窗放上去,然后找到这最开始的k个数的最大值,然后窗最后移一个单元,继续找到k个数中的最大值。

这种方法每求一个f(i),都要进行k-1次的比较,复杂度为O(N*k)。

那么有没有更快一点的算法呢?

解法二:

我们知道,上一种算法有一个地方是重复比较了,就是在找当前的f(i)的时候,i的前面k-1个数其它在算f(i-1)的时候我们就比较过了。那么我们能不能保存上一次的结果呢?当然主要是i的前k-1个数中的最大值了。答案是可以,这就要用到单调递减队列。

单调递减队列是这么一个队列,它的头元素一直是队列当中的最大值,而且队列中的值是按照递减的顺序排列的。我们可以从队列的末尾插入一个元素,可以从队列的两端删除元素。

1.首先看插入元素:为了保证队列的递减性,我们在插入元素v的时候,要将队尾的元素和v比较,如果队尾的元素不大于v,则删除队尾的元素,然后继续将新的队尾的元素与v比较,直到队尾的元素大于v,这个时候我们才将v插入到队尾。

2.队尾的删除刚刚已经说了,那么队首的元素什么时候删除呢?由于我们只需要保存i的前k-1个元素中的最大值,所以当队首的元素的索引或下标小于i-k+1的时候,就说明队首的元素对于求f(i)已经没有意义了,因为它已经不在窗里面了。所以当index[队首元素]<i-k+1时,将队首元素删除。

 

从上面的介绍当中,我们知道,单调队列与队列唯一的不同就在于它不仅要保存元素的值,而且要保存元素的索引(当然在实际应用中我们可以只需要保存索引,而通过索引间接找到当前索引的值)。

为了让读者更明白一点,我举个简单的例子。

假设数列为:8,7,12,5,16,9,17,2,4,6.N=10,k=3.

那么我们构造一个长度为3的单调递减队列:

首先,那8和它的索引0放入队列中,我们用(8,0)表示,每一步插入元素时队列中的元素如下:

0:插入8,队列为:(8,0)

1:插入7,队列为:(8,0),(7,1)

2:插入12,队列为:(12,2)

3:插入5,队列为:(12,2),(5,3)

4:插入16,队列为:(16,4)

5:插入9,队列为:(16,4),(9,5)

。。。。依此类推

那么f(i)就是第i步时队列当中的首元素:8,8,12,12,16,16,。。。

程序代码如下:

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/153008.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Java爬虫系列四:使用selenium-java爬取js异步请求的数据[通俗易懂]

    在之前的系列文章中介绍了如何使用httpclient抓取页面html以及如何用jsoup分析html源文件内容得到我们想要的数据,但是有时候通过这两种方式不能正常抓取到我们想要的数据,比如看如下例子。

    2022年2月16日
    70
  • 分布式文件存储的实现

    分布式文件存储的实现分布式文件存储的实现

    2022年5月9日
    43
  • layui 树形表格 treeTable使用详细指南,不能折叠解决办法

    layui 树形表格 treeTable使用详细指南,不能折叠解决办法最近在写一个商品分类管理的功能,本来想用layui的树形组件来写,但发现layui原生的tree只能展示title,而分类的其他字段无法展示,这就有点不适用了,无意中看到一位大神自定义写的一个树形表格组件,正好满足我的要求,特此将使用方法以及其中遇到的一些坑记录下来。。。首先看下treeTable的演示地址项目地址好了,如果看完演示到这里你觉得正好符合你的功能要求,就可以继续往下看了,虽…

    2022年5月4日
    103
  • Ubuntu安装显卡驱动教程

    Ubuntu安装显卡驱动教程一 参考资料环境搭建 01 Ubuntu16 04 如何查看显卡信息及安装 NVDIA 显卡驱动二 环境配置系统 Ubuntu16 04 显卡 NVIDIAGeForc 4GB 三 准备工作 1 根据电脑显卡型号 下载对应显卡驱动下载链接 博主对应下载的驱动版本 NVIDIA Linux x86 64 470 57 02 run2 将显卡驱动放到 home yichao Downloads 目录四 关键步骤 1 查看显卡型号 驱动 查看显卡型号 ubuntu

    2025年6月17日
    4
  • 神奇的CSS3按钮特效

    点击这里查看效果以下是源代码:1234567CSS3神奇的按钮-柯乐义89678695696697请使用支持CSS3的浏览器查看本页。原文698699700701

    2021年12月20日
    51
  • windows10 记事本进程 键盘消息钩子 dll注入

    windows10 记事本进程 键盘消息钩子 dll注入看了很多文档,垮了很多坎,终于完成了这个demo;有很多个人理解,可能不完全正确,见谅;先上实现的图片:如图,我通过SetWindowsHookEx()函数向记事本进程中当前窗口线程注入了自己写的dll,dll中设置的回调函数使,当键盘按了1,那么就会触发一个MessageBox。工具:VS2015,PCHunter(用于查看是否成功注入了dll,其实看能否实现功能就信…

    2022年7月26日
    16

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号