简介
- 单调栈即为有序栈,分为单调递增和单调递减。
- 最大好处是时间复杂度是线性的,每个元素遍历一次
实现伪代码
stack<int> st;
for (遍历这个数组)
{
if (栈空 || 栈顶元素大于等于当前比较元素)
{
入栈;
}
else
{
while (栈不为空 && 栈顶元素小于当前元素)
{
栈顶元素出栈;
更新结果;
}
当前数据入栈;
}
}
举例
84. 柱状图中最大的矩形
基本思路
- 遍历每一根柱子,矩形高为当前柱子的高,宽度为左右第一个高度小于当前柱子的柱子距离差。
- 记录每一个矩形大小,对比出最大值。
- 暴力算法时间复杂度O(N^2)
优化思路
- 暴力算法中使用双重循环分别遍历了当前柱子左侧与右侧的柱子,寻找第一个高度小于当前柱子的柱子(左边沿和右边沿)。
- 如果遍历每根柱子时记录下左侧比当前柱子小的柱子,则可以省去一个循环,这一步从O(N)变成O(1)。
- 使用单调栈,若当前的柱子高度大于等于栈顶柱子的高度,就直接将当前柱子入栈。若当前的柱子高度小于栈顶柱子的高度,则当前柱子为当前栈顶柱子A右边沿,A出栈,此后栈顶柱子为A的左边沿。
- 此时以栈顶柱子为高的,左右边沿柱子就确定了,可以计算面积。
- 在原数组左右各加入一个高度为0的柱子,避免无法让所有高度全出栈。
优化后代码
class Solution {
public int largestRectangleArea(int[] heights) {
int[] tmp = new int[heights.length + 2];
System.arraycopy(heights, 0, tmp, 1, heights.length);
int n = tmp.length;
Deque<Integer> stack = new ArrayDeque<>();
int res = 0;
for (int i = 0; i < n; i++) {
while(!stack.isEmpty() && tmp[i] < tmp[stack.peek()]) {
int h = tmp[stack.pop()];
res = Math.max(res, (i - stack.peek() -1) * h);
}
stack.push(i);
}
return res;
}
}
参考