单调栈解决柱状图及引申问题

本文探讨了如何利用单调栈优化算法解决柱状图中最大矩形面积问题,以及二维矩阵中最大由1组成的矩阵。通过维护递增栈来快速找到边界,避免了传统穷举方法的时间复杂度。实例解析了两种场景的解决方案,提升了解题效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

84 柱状图中最大的矩形

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。
如图:
在这里插入图片描述
这题乍一看我都以为是动态规划,但是仔细分析发现好像最优子结构并不适合状态转移。那么思路可能就是穷举:
1) 枚举宽w,那么就是一个二重循环来确定,对每个循环中找出相应最矮的那个柱子,那么就是对应的最大矩阵。
2)枚举高h,通过向左右延伸找到比它更小的高度值,就是该高度对应的最大矩阵。
穷举一下时间复杂度高达O(m * n), 那估计是要超时了。
进一步思考,对于枚举高度hi,我们向左右延伸时找到左右两侧最近的高度小于 h 的柱子,这样这两根柱子之间(不包括其本身)的所有柱子高度均不小于 h,并且就是 i能够扩展到的最远范围。

对于两根柱子i, j ,高度i是大于高度j的,那么在j之后出现的柱子一定不会以i作为它的左边界。那么我们只需维护一组递增数,当对于当前枚举的高度在这组数中向前找到第一个比他小的即可。

一组递增序列的维护肯定就是单调栈了:
单调栈可以分为递增单调栈以及递减单调栈,对于到来的数pop比他大/小的值,再将其push进栈。

 for(int i = 0; i < n; i++) {
            while(!stack.isEmpty() && arr[stack.peek()] >= arr[i]) {
                stack.pop();
            }
            stack.push(i);
        }
// --------------------------------------------------------------
 for(int i = 0; i < n; i++) {
            while(!stack.isEmpty() && arr[stack.peek()] <= arr[i]) {
                stack.pop();
            }
            stack.push(i);
        }

那么对于上面这题解决就很方便了,只需对于枚举的高度,找出其对应的左边界;再以同样的方法获得其有边界。

public int largestRectangleArea(int[] heights) {
        int n =heights.length;
        int[] left = new int[n];
        int[] right = new int[n];
		// LinkedList当栈使用
        Deque<Integer> stack = new LinkedList<>();
        for(int i = 0; i < n; i++) {
            while(!stack.isEmpty() && heights[stack.peek()] >= heights[i]) {
                stack.pop();
            }
            left[i] = (stack.isEmpty() ? -1 : stack.peek());
            stack.push(i);
        }
        stack.clear();
        for(int i = n - 1; i >= 0; i--) {
           while(!stack.isEmpty() && heights[stack.peek()] >= heights[i]) {
               stack.pop();
            }
            right[i] = stack.isEmpty() ? n : stack.peek();
            stack.push(i);
        }
        int res = 0;
        for(int i = 0; i < n; i++) {
            int sum = (right[i] - left[i] - 1) * heights[i];
            res = Math.max(res, sum);
        }
        return res;
    }

85 最大矩形

再看一题,给定一个二维矩阵由0,1组成,要找出其中最大的由 1 组成的矩阵。
在这里插入图片描述

在一个二维下,找出最大矩阵,用柱状图的方法是可以解决的。
那又该以什么作为“高”来枚举呢?
对于每行的“1”我们可以将其连续的“1” 作为所在位置的最大宽度maxWeight,那么高度就是在这位置(i, j)基础上上下延伸来枚举,找到符合的最小宽度的那个maxWeight,似乎可行。
使用单调栈进行维护这个maxWeight宽度序列,来找出当前位置上的最小宽度。

// 枚举高度 矩阵的列作为高度
 for(int j = 0; j < n; j++) {
            int[] up = new int[m];
            int[] down = new int[m];

            Deque<Integer> stack = new LinkedList<>();
            for(int i = 0; i < m; i++) {
                while(!stack.isEmpty() && left[stack.peek()][j] >= left[i][j]) {
                    stack.pop();
                }
                up[i] = stack.isEmpty() ? -1 : stack.peek();
                stack.push(i);
            }
            stack.clear();
            for(int i = m - 1; i >= 0; i--) {
                while(!stack.isEmpty() && left[stack.peek()][j] >= left[i][j]) {
                    stack.pop();
                }
                down[i] = stack.isEmpty() ? m : stack.peek();
                stack.push(i);
            }

最后遍历比较出最大的那个矩阵即可。

力扣题链接:
84 柱状图中最大的矩形
85 最大矩形

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值