人人都能学会的编程入门课
胡光
原百度高级算法研发工程师
19410 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 38 讲
开篇词 (1讲)
人人都能学会的编程入门课
15
15
1.0x
00:00/00:00
登录|注册

21 | 队列与单调队列:滑动区间最大值

你好,我是胡光,欢迎回来。
上节课呢,我们学习了二分查找的基本思想,以及明确了二分答案所使用的问题模型,你会发现,正因为问题具有单调性,我们才可以使用二分查找算法对问题求解过程进行加速。
今天呢,我将带你学习一种性质有趣、简单且高效的数据结构,叫做:单调队列。学习这个数据结构的时候呢,我们还是要强调一下那句话:数据结构,就是定义一种性质,并且维护这种性质。

今日任务

在正式开始学习之前呢,先来看一下今天这 10 分钟的任务吧。
滑动区间最大值,就是指在固定区间长度的前提下,在一个序列上,从前到后滑动这个区间窗口,每次窗口内部的最大值,就组成了滑动区间最大值。
例如,给你如下包含 8 个数字的序列,区间长度设置为 3:
[6 4 2] 10 3 8 5 9 -> 6
6 [4 2 10] 3 8 5 9 -> 10
6 4 [2 10 3] 8 5 9 -> 10
6 4 2 [10 3 8] 5 9 -> 10
6 4 2 10 [3 8 5] 9 -> 8
6 4 2 10 3 [8 5 9] -> 9
滑动区间从数字 6 开始出发,每次向右移动一个数字,同时把左边的一个数字丢出去,保持区间长度为 3,最后移动到数字 9 停止。可以看到,这个序列共包含 8 个数字,所以最后形成的滑动区间最大值共有 6 个,依次是 6、10、10、10、8、9。
面对这个问题,你很容易采用 的算法来完成,n 是区间长度,m 是窗口长度,就是枚举区间的终止位置,每次扫描区间内部,获得最大值。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

单调队列:高效解决滑动区间最大值问题 本文介绍了单调队列这一高效的数据结构,以及其在解决滑动区间最大值问题中的应用。作者首先引出了滑动区间最大值的概念,并指出了传统算法的时间复杂度问题。随后,详细讲解了队列和单调队列的概念,以及单调队列在维护区间最大值时的应用。通过生动的比喻,将单调队列比作校队名单,解释了其维护区间最大值的原理。强调了单调队列的作用,以及其在解决滑动区间最大值问题中的高效性。代码示例展示了单调队列的具体应用,以及其在维护区间最大值时的实现方法。最后,强调了单调队列的处理单个元素的平均时间复杂度为O(1),并展望了下节课关于“栈”的知识。整体而言,本文通过生动的比喻和清晰的逻辑,向读者介绍了单调队列的概念及其在实际问题中的应用,为读者提供了一种新的解决问题的思路和方法。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《人人都能学会的编程入门课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(7)

  • 最新
  • 精选
  • 宋不肥
    老师,我目前在北京某985读书,平时实验室做得机器学习,大部分代码就是简单得把矩阵运算翻译成matlab和python,但感觉除了matlab其他得编程语言都写得很业余,想来是自己非科班不够努力,同时其他语言对计算得封装是不如matlab完善的。但应该什么样的训练方法可以快速提高呢?本科偏数学,毕业后想去大厂面试(机器学习&深度学习)算法岗,大概还有5年的硕博学习时间,除了数学上的持续学习,(计算机科班培养计划这边学习了geek的深入理解计算机原理,在啃推荐的那本《深入理解计算机系统》,也在和这门课同时学习geek的数据结构与算法之美,看懂容易,自己上手就有点难度了,基本上跟着抄一边)计算机科班的东西我应该主要补一下哪些内容呢?有什么好的学习路径的推荐和学习建议吗?希望老师能指点一下,万分感谢!

    作者回复: 你好,听了你的情况,我对你的判断是,你的理论知识应该是很扎实的,只是缺少实践经验,建议如下: 1、平时多在 Linux 系统下学习和工作,可以选择 CentOS 或者 Ubuntu 均可 2、试着使用 github 上传自己用 python 封装的机器学习模型算法 3、如果有条件,尽量的在分布式环境下跑跑算法,课外有时间的话,可以读一读分布式计算与并行计算方面的东西。 只能给你如上建议了,仅供参考。

    2020-03-08
    1
  • 🤪HappyJoo
    老师不好意思,我知道我代码出错的概率大很多很多: 输入:nums = [1,3,-1,-3,5,3,6,7], n = 8, m = 3 错误输出:[3, 3, 5, 3, 6, 7] 正确输出:[3, 3, 5, 5, 6, 7] 第四项不知道为啥错了,是copy您的代码然后输出的,不知道是不是您的代码哪里写错了。当然,更大可能是我的代码写错了(笑哭)。看了两个多小时了呀,都看不懂这段代码,我是不是太钻牛角尖了(笑哭)。 https://github.com/HappyJoo/CLearningScript/blob/master/Heap/239_Sliding_window_maximum.cpp

    作者回复: 不是你的错误,你的是对的!是我代码的问题,队列中最后一个元素应该是,q[tail - 1],最近疫情,都把我在家呆傻了。-_-||| sorry

    2020-03-05
    2
    1
  • Geek_79bb26
    老师好,我还是没理解单调数列里单调性的概念,比如老师给的例程,q数组里应该存储的是滑动窗口中a数组最大值对应的序号值,以6 4 2] 10 3 8 5 9,应该是0,3,5,7(序号),那么q里这个数组单调性体现在哪儿呢?只能是滑动窗口值是单调的。理解力不好,谢谢老师

    作者回复: 首先理解单调队列,你要先忽略掉底层实现。单调队列中,就是维护元素某个维度上的单调性。不是维护序号的单调性,因为序号一定是单调出现的,不需要维护,你想想这个逻辑。

    2020-07-14
  • 1043
    老师讲的算法用数学语言去理解感觉讲的太到位了,很好理解,但是再去转换成机器思维好像就不知道如何表达了……听了老师今天的课感觉在入门编程之前应该先再去学学入门前的入门课,比如数据结构,基础算法,组成原理,微积分、离散数学等等;感觉真是正如高德纳大师——冯诺依曼之后最伟大的计算机科学家说的如果连《计算机程序设计艺术》的卷一都学不懂干脆就别当程序员了。另外高德纳大师说的“只要不是对计算机只有一时兴趣的人,都应该学好机器语言,这是计算机的基础。”这个说法正对上了和胡光老师说的“学习编程,与其说是将我们的思维转换成代码,不如说是将我们的思维,锻炼成计算机的思维。”胡老师和高德纳老师的这个训练机器思维如出一辙呀!那么问题来了,如和才能用正确的姿势学好那天书一样的机器语言呢?

    作者回复: 注重学习计算机问题的处理顺序。这是第一步,代表了计算机的思考顺序。就像栈和队列,以及之前所学习的链表,其实都代表了按照某种顺序处理问题的思想。

    2020-04-17
  • 🤪HappyJoo
    老师你好啊~我现在不知道要看啥,c专家与编程好像还早了点,课程其他内容虽然还没有完全消化,但是也差不多了,有点不知道应该干什么,去leetcode刷题吗?还是看一些例如C与指针,啃一下大部头?还是去看看《数据结构与算法之美》,或者《深入了解计算机原理》,或者《编译原理之美》?又或者去看看python?有点不知道要走哪个方向,迷茫~

    作者回复: 你的目标是啥呢?

    2020-03-05
    12
  • 罗耀龙@坐忘
    茶艺师学编程 1、“数据结构,就是定义一种结构,并且维护这个结构。”这句话值得好好品味。 2、初看老师的给的代码,我是蒙的,为什么不是直接的a[n]而是要a[q[n]],后来才回过神来,例子中的的q[n]是坐标轴,区间滑动就是在它上面进行的,a[q[n]]才这个轴的值。这里可以打个比方,就是我要到某青年旅馆找我的朋友a[q[n]],朋友给了我他的房间号(q[n])。我比对了n个房间号,终于找到q[n]房号,这才敲门进屋,看见我的朋友a[q[n]],而不是没每到一个房间前就踹门而进看看里面是什么人。 文中例子的完整可行代码如下: #include <stdio.h> #define MAX_N 1000 int q[MAX_N + 5], head, tail; void interval_max_number(int *a, int n, int m){ head = tail = 0; for (int i = 0; i < n; i++){ while (head < tail && a[q[tail - 1]] < a[i])tail--; q[tail++] = i; if (i - m == q[head])head++; if(i + 1 >= m){ printf("interval(%d, %d)", i - m + 1, i); printf(" = %d\n", a[q[head]]); } } return ; } int main(){ int a[8] = {6, 4, 2, 10, 3, 8, 5, 9}; int n = 8; int m = 3; interval_max_number(a, n, m); return 0 ; }
    2020-10-09
    1
  • doge
    在这个最大值单调队列维护的过程中有2个点: 1、元素在区间最大; 2、元素是否已经过期。 最开始直接在单调队列存数值本身,结果发现判断过期还需要额外的空间 后面反应过来来用索引既能获得数值也能判断过期 这个是我在思维上的一个槛,不知道啥时候才能自然跨过这个问题
    2020-10-16
收起评论
显示
设置
留言
7
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部