深刻浅出搞通单调队列单调栈

下面咱们经过几个题目由浅入深,一点一点挖透他们吧!数组

图片

提纲
app

单调队列

剑指 Offer 59 - II. 队列的最大值

题目描述:

请定义一个队列并实现函数 max_value 获得队列里的最大值ide

若队列为空,pop_front 和 max_value 须要返回 -1函数

示例 1:spa

输入: ["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]设计

[[],[1],[2],[],[],[]] 3d

输出: [null,null,null,2,1,2]code

示例 2:orm

输入: 视频

["MaxQueue","pop_front","max_value"] 

[[],[],[]] 

输出: [null,-1,-1]

题目解析:

咱们先来拆解下上面的示例 1


其实我以为这个题目的重点在理解题意上面,可能刚开始刷题的同窗,对题意理解不够透彻,作起来没有那么驾轻就熟,经过上面的图片咱们简单了解了一下题意,那咱们应该怎么作才能实现上述要求呢?

下面咱们来讲一下双端队列。咱们以前说过的队列,遵照先进先出的规则,双端队列则能够从队头出队,也能够从队尾出队,不用遵照先进先出的规则,咱们先经过一个视频来简单了解下双端队列。



咱们能够用双端队列作辅助队列,用辅助队列来保存当前队列的最大值。咱们同时定义一个普通队列和一个双端单调队列。普通队列就正常执行入队,出队操做。max_value 操做则返回我们的双端队列的队头便可。下面咱们来看一下代码的具体执行过程吧。




咱们来对视频进行解析

1.咱们须要维护一个单调双端队列,上面的队列则执行正常操做,下面的队列队头元素则为上面队列的最大值

2.出队时,咱们须要进行对比两个队列的队头元素是否相等,若是相等则同时出队,则出队后的双端队列的头部仍为上面队列中的最大值。

3.入队时,咱们须要维持一个单调递减的双端队列,由于咱们须要确保队头元素为最大值嘛。

题目代码:

图片

239.滑动窗口最大值

题目描述:

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

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

示例1:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7]

题目解析:

题目让咱们找出每一个滑动窗口的最大值,那么题目具体含义是怎样呢?

图片

就是为了让咱们输出每一个窗口的最大值,那咱们思考一下,咱们一个数组一共有多少窗口呢?

好比咱们这个例子中,咱们的窗口长度为 3 ,数组长度为 8,咱们的窗口每次移动一位,因此咱们一共有 8 - (3 - 1)也就是  8 - 3 + 1。因此咱们返回数组的长度是跟原数组长度和滑动窗口的长度有关的。

也就是 winlen =  len(数组长度) - k(滑动窗口长度) + 1。下面咱们来看一个视频,相信经过这个视频,你们一下就能搞懂啦。



1.先将咱们第一个窗口的全部值按照规则存入单调双端队列中,单调队列里面的值为单调递减的。若是发现队尾元素小于要加入的元素,则将队尾元素出队,直到队尾元素大于等于新元素时,再让新元素入队,目的就是维护一个单调递减的队列。第一个窗口的全部值入队以后状况,以下图。是由于 3 要入队时,此时队中有 1 ,不能保证单调递减,因此须要 1 出队,而后 3 入队, -1  入队时,队中有 3 ,知足单调,因此  -1  能够入队。

图片

2.咱们将第一个窗口的全部值,按照单调队列的规则入队以后,由于队列为单调递减,因此队头元素必为当前窗口的最大值,则将队头元素添加到数组中。

图片

3.移动窗口,判断当前窗口前的元素是否和双端队列队头元素相等,若是相等则出队,此时滑动窗口的最大值发生改变了。

图片

4.继续而后按照规则进行入队,维护单调递减队列,这里和第一条规则一致。

5.每次将队头元素存到返回数组里。

6.返回数组

是否是一下就搞懂啦。你真帅,下面咱们来看一下代码吧。

题目代码

图片


单调栈

leetcode 155 最小栈

设计一个支持 push ,pop ,top 操做,并能在常数时间内检索到最小元素的栈。

  • push(x) —— 将元素 x 推入栈中。
  • pop() —— 删除栈顶的元素。
  • top() —— 获取栈顶元素。
  • getMin() —— 检索栈中的最小元素。

输入:

["MinStack","push","push","push","getMin","pop","top","getMin"]

[[],[-2],[0],[-3],[],[],[],[]]

输出:

[null,null,null,null,-3,null,0,-2]

题目解析

感受这个题目的难度就在读懂题意上面,读懂以后就没有什么难的了,咱们在上面的滑动窗口的最大值已经进行了详细描述,其实这个题目和那个题目思路一致。

该题让咱们设计一个栈,该栈具备的功能有,push,pop,top等操做,而且可以返回栈的最小值。好比此时栈中的元素为 5,1,2,3。咱们执行 getMin()  ,则可以返回 1。这块是这个题目的精髓所在,见下图, 这个题目也能够不利用辅助栈解决,可是不符合本文主题,因此在这里先不进行详细描述。大体思路为,把当前最小值用一个变量保存,须要入栈的值小于当前最小值时,先把当前最小值入栈,再将须要入栈的值入栈,并更新当前最小值。若是大于当前最小值,则直接入栈。getMin() 函数则直接返回变量保存的值便可。下面咱们来看一下咱们借助辅助栈,如何解决这个题目吧。

图片


1.咱们执行入栈操做时,先观察须要入栈的元素是否小于栈 B 的栈顶元素,若是小于则两个栈都执行入栈操做。

2.栈 B 的栈顶元素则是栈 A 此时的最小值。则 getMin() 只需返回栈 B 的栈顶元素便可。

3.出栈时,须要进行对比,若栈 A 和栈 B 栈顶元素相同,则同时出栈,出栈后B 的栈顶保存的仍为此时栈 A 的最小元素

题目代码

图片


leetcode 739 每日温度

题目描述:

请根据每日 气温 列表,从新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少须要等待的天数。若是气温在这以后都不会升高,请在该位置用 0 来代替。

示例1:

输入:temperatures = [73, 74, 75, 71, 69, 72, 76, 73]

输出:arr =   [1, 1, 4, 2, 1, 1, 0, 0]

示例2:

输入:temperatures = [30,30,31,45,31,34,56]

输出:arr =   [2,1,1,3,1,1,0]

题目解析

其实咱们能够换种方式理解这个题目,好比咱们 temperatures[0] = 30,则咱们须要找到后面第一个比 30 大的数,也就是 31,31的下标为 2,30 的下标为 0 ,则咱们的返回数组 arr[0] = 2。理解了题目以后咱们来讲一下解题思路。

遍历数组,数组中的值为待入栈元素,待入栈元素入栈时会先跟栈顶元素进行对比,若是小于等于该值则入栈,若是大于则将栈顶元素出栈,新的元素入栈。

例如栈顶为69,新的元素为72,则69出栈,72入栈。并赋值给 arr,69 的索引为4,72的索引为5,则 arr[4] = 5 - 4 = 1,这个题目用到的是单调栈的思想.

注:栈中的括号内的值,表明索引对应的元素,咱们的入栈的为索引值,为了便于理解将其对应的值写在了括号中



leetcode 42 接雨水

这道接雨水也是一道特别经典的题目,一道必刷题目,咱们也用单调栈来解决。下面咱们来看一下题目吧

题目描述:

给定 n 个非负整数表示每一个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨以后能接多少雨水。


示例1:

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]

输出:6

示例2:

输入:height = [4,2,0,3,2,5]

输出:9

示例2:

输入:[4,3,2,0,1,1,5

输出:13

题目解析:

看了上面的示例刚开始刷题的同窗可能有些懵逼,那咱们结合图片来理解一下,咱们就用示例3的例子进行举例,他的雨水到底表明的是什么。输入表明的是黄色箱子的个数,蓝色箱子表明雨水数量。缝隙之间能够装多少水

图片

说明:上面是由数组 [4,3,2,0,1,1,5]表示的高度图,在这种状况下,能够接 13个单位的雨水(见下图)。

上图则为咱们的题目描述,是否是理解了呢?你也能够这样理解咱们在地上放置了若干高度的黄色箱子,他们中间有空隙,而后咱们想在他们里面插入若干蓝色箱子,并保证插入以后,这些箱子的左视图和右视图都不能看到蓝色箱子。
好啦题目咱们已经理解了,下面咱们来看一下接雨水问题到底该怎么作,其实原理也很简单,咱们经过咱们的例3来进行说明。
首先咱们依次入栈4,3,2,0咱们的数组前四个元素是符合单调栈规则的。可是咱们的第五个1,是大于0的。那咱们就须要0出栈1入栈。可是咱们这样作是为了什么呢?有什么意义呢?别急咱们来看下图。

图片

上图咱们的,4,3,2,0已经入栈了,咱们的另外一个元素为1,栈顶元素为0,栈顶下的元素为2。那么咱们在这一层接到的雨水数量怎么算呢?2,0,1这三个元素能够接住的水为一个单位(见下图)这是咱们第一层接到水的数量
注:能接到水的状况,确定是中间低两边高的状况

图片


由于咱们须要维护一个单调栈,因此咱们则须要将0出栈1入栈,那么此时栈内元素为4,3,2,1。下一位元素为1,咱们入栈,此时栈内元素为4,3,2,1,1。下一元素为5,栈顶元素为1,栈顶的下一元素仍为1,则须要再下一个元素,为2,那咱们求当前层接到的水的数量。
注:栈内保存的应是索引值,这里为了便于理解用了value值

图片


咱们是经过2,1,1,5这四个元素求得第二层的接水数为1*3=3;1是由于min(2-1,5-1)=min(1,4)得来的,你们能够思考一下木桶效应。装水的多少,确定是按最短的那个木板来的,因此高度为1,3的话是由于5的索引为6,2的索引为2,他们之间共有三个元素(3,4,5)也就是3个单位。因此为6-2-1=3。将1出栈以后,咱们栈顶元素就变成了2,下一元素变成了3,那么3,2,5这三个元素一样也能够接到水。

图片


这是第三层的接水状况,可以接到4个单位的水,下面咱们继续出栈2,那么咱们的4,3,5仍然能够接到水啊。

图片

这是咱们第四层接水的状况,一共可以接到5个单位的水,那么咱们总的接水数加起来,那就是1+3+4+5=13。你学会了吗?别急还有动图咱们,咱们再来深刻理解一哈。


题目代码:


图片

相关文章
相关标签/搜索