3.1 单调栈-局部顺序
单调栈
- 用来解决局部顺序问题
- 柱形图问题多使用单调栈。
下边是对柱形图问题的总结。
- 视野总和:利用了栈内元素的数量计算问题。
- 柱形图中的最大矩形:利用的是出栈序列。这组序列构成了可能的最大矩形。
- 盛最多水的容器:利用了反向贪心思想。
- 接雨水问题:单调栈解法也是利用了出栈序列。这个序列的左右边界能够形成一个容器。双指针解法利用了反向贪心思想。
- 接雨水问题2
其它类型的单调栈
1 视野总和
问题描述
- 有n个人站队,所有的人全部向右看,个子高的可以看到个子低的发型,给出每个人的身高,问所有人能看到其他人发现总和是多少。
1 | 输入:4 3 7 1 |
问题分析
- 问题分类:
- 思路:观察题之后,我们发现实际上题目转化为找当前数字向右查找的第一个大于他的数字之间有多少个数字,然后将每个结果累计就是答案,但是这里时间复杂度为O(N^2),所以我们使用单调栈来解决这个问题。
策略选择
- 数据结构:单调栈
- 算法思想:局部降序统计
算法设计
- 设置一个单调递减栈
- 当入栈的的时候,栈内的人肯定能看到该元素。
利用了栈内元素的数量,解决问题。
算法分析
- 时间复杂度为O(N)
- 空间复杂度O(N)
算法实现
1 | int FieldSum(vector<int>& v) |
2 柱状图中的最大矩形
问题描述

问题分析
策略选择
- 思路:当前的数字可以向两边拓展,遇到比自己大的就接着拓展,小的就停止,然后用自己的高度乘以拓展的宽度,每次更新最大面积,时间复杂度同样为O(N^2),所以我们接着借助单调栈
算法设计
- 设置一个单调递增栈
- 当遇到小于栈顶元素的值,我们开始更新数据,因为有可能最大面积就会出现在栈中的序列里
- 牢记栈中数据永远是有序的,这个问题比较复杂,所以读者不妨对照着代码来理解问题
算法分析
- 时间复杂度为O(N)
- 空间复杂度O(N)
算法实现
1 | int largestRectangleArea(vector<int>& heights) { |
3 求最大区间
问题描述
- 描述:给出一组数字,求一区间,使得区间元素和乘以区间最小值最大,结果要求给出这个最大值和区间的左右端点
1 | 输入:3 1 6 4 5 2 |
- 解释:将3到5(6+4+5)这段区间相加,将和与区间内最小元素相乘获得最大数字60
问题分析
策略选择
- 思路:使用暴力解法求出所有区间,再求出区间的最小值相乘跟新数据,并不是一种很好的算法
算法设计
- 设置一个单调递增栈
- 当遇到小于栈顶元素的值,我们开始更新数据,因为当前遇到的值一定是当前序列最小的
算法分析
- 时间复杂度O(n)
- 空间复杂度O(n)
算法实现
1 | int GetMaxSequence(vector<int>& v) |
4 132 模式
问题描述
给你一个整数数组 nums ,数组中共有 n 个整数。132 模式的子序列 由三个整数 nums[i]、nums[j] 和 nums[k] 组成,并同时满足:i < j < k 和 nums[i] < nums[k] < nums[j] 。
如果 nums 中存在 132 模式的子序列 ,返回 true ;否则,返回 false 。
进阶:很容易想到时间复杂度为 O(n^2) 的解决方案,你可以设计一个时间复杂度为 O(n logn) 或 O(n) 的解决方案吗?
示例 1:
1 | 输入:nums = [1,2,3,4] |
- 示例 2:
1 | 输入:nums = [3,1,4,2] |
问题分析
策略选择
算法设计
因此,我们可以使用单调栈作为维护 2 的数据结构,并给出下面的算法:
我们用单调栈维护所有可以作为 2 的候选元素。初始时,单调栈中只有唯一的元素 $\textit{a}[n-1]$。我们还需要使用一个变量 $\textit{max_k}$max_ 记录所有可以真正作为 2 的元素的最大值;
随后我们从 n-2开始从右到左枚举元素 a[i]:
首先我们判断 a[i]是否可以作为 1。如果 $a[i] < \textit{max_k}$,那么它就可以作为 1,我们就找到了一组满足 132模式的三元组;
随后我们判断 a[i]a[i] 是否可以作为 33,以此找出哪些可以真正作为 22 的元素。我们将 a[i]a[i] 不断地与单调栈栈顶的元素进行比较,如果 a[i]a[i] 较大,那么栈顶元素可以真正作为 22,将其弹出并更新 \textit{max_k}max_k;
最后我们将 a[i]a[i] 作为 22 的候选元素放入单调栈中。这里可以进行一个优化,即如果 a[i] \leq \textit{max_k}a[i]≤max_k,那么我们也没有必要将 a[i]a[i] 放入栈中,因为即使它在未来被弹出,也不会将 \textit{max_k}max_k 更新为更大的值。
在枚举完所有的元素后,如果仍未找到满足 132132 模式的三元组,那就说明其不存在。
算法分析
- 时间复杂度:O(n)。
- 空间复杂度:O(n)
算法实现
1 | class Solution { |
5 包含min函数的栈
问题描述
- 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
示例:
1 | MinStack minStack = new MinStack(); |
提示:各函数的调用总次数不超过 20000 次
问题分析
策略选择
算法设计
- 将 min() 函数复杂度降为 O(1)O(1) ,可通过建立辅助栈实现;
- 数据栈 AA : 栈 AA 用于存储所有元素,保证入栈 push() 函数、出栈 pop() 函数、获取栈顶 top() 函数的正常逻辑。
- 辅助栈 BB : 栈 BB 中存储栈 AA 中所有 非严格降序 的元素,则栈 AA 中的最小元素始终对应栈 BB 的栈顶元素,即 min() 函数只需返回栈 BB 的栈顶元素即可。
- 因此,只需设法维护好 栈 BB 的元素,使其保持非严格降序,即可实现 min() 函数的 O(1)O(1) 复杂度。

算法分析
算法实现
1 | class MinStack { |









