力扣 Top100 84. 柱状图中最大的矩形

题目来源:https://leetcode-cn.com/problems/largest-rectangle-in-histogram/

大致题意:
给定一个数组,表示每个位置的柱形高度,假设所有柱形的宽度为 1,求它们能构成的最大矩形的面积

思路

对于每个位置,若能求出以其为高度的矩形的长度,那么就可以求出该矩形的面积,相应的,对于所有位置进行这样的运算,就可以得到矩形的最大面积

如何求出相应高度矩形的长度?

  • 可以使用单调栈求出两侧最近的小于当前高度矩形位置 i 和 j,那么中间的部分的高度都大于或等于当前位置的高度,因而可以求出矩形的长度为 j - i + 1
单调栈
  1. 使用两个数组 left 和 right,left 存每个位置左侧的小于当前高度的位置(即左边界,若没有则为 -1),right 存每个位置右侧小于当前高度的位置(即右边界,若没有则为数组长度 n)
  2. 正向遍历,使用一个单调栈存柱形高度的上升子序列,栈中存下对应索引。 每次遍历,在单调栈中找出左侧第一个最近的小于当前高度的位置(即栈顶元素对应高度小于当前高度,如果不满足,则栈顶元素出栈),若没有则为 -1。求出边界后,将当前位置入栈
  3. 反向遍历,使用一个单调栈存柱形高度的逆序上升子序列,栈中存下对应索引。 每次遍历,在单调栈中找出第一个最近的小于当前高度的位置(即栈顶元素对应高度小于当前高度,如果不满足,则栈顶元素出栈),若没有则为数组长度 n。求出边界后,将当前位置入栈
  4. 遍历数组 left 和 right,每个位置对应的矩形的最大面积即为:当前位置的高度 * (right[i] - left[i] - 1)。求出最大的矩形面积

具体的,可以发现正向遍历时,每次出栈的元素,其右侧最近的小于等于其的位置即为当前位置,因为若当前位置高度不是最近的小于等于出栈元素高度的,那在之前该元素就已经出栈了。所以可以在出栈的时候确定出栈元素对应的右侧最近的小于等于其的位置。
可以注意到,我们之前求的是右侧小于当前高度的位置(右边界),而不是小于等于,因而部分右边界是错误的。但是这不影响最终结果,因为相等高度的最右侧位置的右边界一定是正确的(因为其右侧元素不是等于,而是小于,和之前一样),而左边界是正确的,所以总能求出正确答案

代码:

class Solution {
    public int largestRectangleArea(int[] heights) {
        
        int n = heights.length;
        int[] left = new int[n];	// 左边界
        int[] right = new int[n];	// 右边界
        Deque<Integer> stack = new ArrayDeque<>();
        Arrays.fill(right, n);	// 初始时都为 n,因为有些位置永远不会出栈
        for (int i = 0; i < n; i++) {
        	// 当单调栈不空,且栈顶元素的高度不小于当前位置高度,出栈
            while (!stack.isEmpty() && heights[stack.peek()] >= heights[i]) {	
            	// 出栈位置右边界即为当前位置
                right[stack.peek()] = i;
                stack.pop();
            }
            // 左边界
            left[i] = stack.isEmpty() ? -1 : stack.peek();
            // 当前位置入栈
            stack.push(i);
        }
        int ans = 0;
        // 求出所有位置对应矩形的面积
        for (int i = 0; i < n; i++) {
            int area = (right[i] - left[i] - 1) * heights[i];
            // 取最大值
            ans = Math.max(area, ans);
        }
        return ans;
    }
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三更鬼

谢谢老板!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值