个人觉得虽然单调栈和单调队列都单调,但是用法和适用的问题却大相径庭。
单调队列
单调队列是指一个队列内部元素具有单调性的数据结构,分为单调递增队列和单调递减队列。
单调队列满足三个性质:
- 单调队列也是队列,满足先进先出
- 单调队列必须满足从队头到队尾的单调性
- 排在队列前面的元素比排在队列后面的元素要先进队
假设一个队列 <– 0 1 3 1 2 5 <–
,简单的理解的话 1 2
这一段对于整个队列的最大值是没有影响的,因为 1 2
先出队,且出队的时候最大值不会变,还是 5 ,所以 1 2
可以直接去掉。
对于单调递增队列,对于一个元素如果它大于等于队尾元素, 那么直接把元素进队, 如果这个元素小于队尾元素,则将队尾元素出队列,直到满足这个元素大于等于队尾元素。
对于单调递减队列,对于一个元素如果它小于等于队尾元素, 那么直接把元素进队, 如果这个元素大于队尾元素,则将队尾元素出队列,直到满足这个元素小于等于队尾元素。
这里我没有强调严格的单调性,因为我认为不递减或不递增是可行的,这个问题要因题目而异。大多数严格的情况下,不加等号的情况下需要保留下标;不是严格的话数据会有冗余,这个要自己取舍~~
实现的话推荐双端队列实现。单调队列应用:
- 均摊 O(1) 的可以获得最大值的队列
- 优化 DP
- 给定一个数列,求长度为 m 的子串(滑动窗口)的最大值或最小值
- 查询区间最大值或者最小值
单调栈
单调栈是指一个栈内部元素具有单调性的数据结构,分为单调递增栈和单调递减栈。
单调栈满足三个性质:
- 单调栈也是栈,满足先进后出。
- 单调栈必须满足从栈顶到栈底的单调性
- 排在栈越下面的元素比排在栈上面的元素要先进栈
栈的实现和队列一模一样,插入模式一样,只有弹出方式不一样。
对于单调递增栈(从栈底到栈顶单调递增),应用:
- 对于一个元素
- 求左边第一个比它小的数
- 求左边第一个比它大的数
- 求右边第一个比他小的数
- 这些数的距离
- 最长的单调区间
- 某个数为最值的最长区间
此外,当访问到第 i 个元素时,单调栈维护的区间为 [0, i) ,而单调队列维护的区间为 (last_pop, i)。
单调队列题目
1 | class MaxQueue |
1 | class Solution |
单调栈题目
目标:对于每一个元素找到左右第一个比他小的元素
当元素一个出栈时,进行比较的新元素是这个元素右边第一个比他小的元素
当元素一个出栈后,新的栈顶元素是这个元素左边第一个比他小的元素
还有,前面和后面记得塞一个0
1 | class Solution |