单调栈

简介

  • 单调栈即为有序栈,分为单调递增和单调递减。
  • 最大好处是时间复杂度是线性的,每个元素遍历一次

实现伪代码

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;
    }
}    

参考

posted @ 2022-03-04 16:54  zjcfrancis  阅读(82)  评论(0编辑  收藏  举报