84:柱状图中最大的矩形

问题描述

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

求在该柱状图中,能够勾勒出来的矩形的最大面积。

在这里插入图片描述
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。
在这里插入图片描述
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。

这题是接雨水的姊妹篇。

示例

输入: [2,1,5,6,2,3]
输出: 10

思路

这题是接雨水的姊妹篇。
这题比接雨水要好想一点,但是也是挺难的。
首先,明确一点,答案肯定是以某个柱子为高度扩展的矩形。所以我们对于每个元素来讲,都向左向右拓展一下,拓展到比它矮的柱子时停止,算一下面积。时间复杂度O(n2)。(方法一)
在方法一中,我们的时间主要花在了对于每个元素都向左向右扩展着去找边界。如果我们有办法读到这个边界的下标,时间复杂度就能继续降低了。
具体来说我们可以维持一个单调栈。它维持的是一个单调不减的栈。
待入栈元素比栈顶元素要小时,证明遇到了右边界,所以可以弹栈以找出左边界。弹栈弹出来是当前高度,我们可以用当前栈中栈顶的元素作为"左边界"。你可能会有疑问,用当前高度的下标来作为左边界不就行吗? 还真不行,必须要用栈顶的元素当做左边界。 因为我们的栈中存储的是迄今为止这个序列中持续保持着不减(非严格递增)的所有元素的下标。那么不符合这个标准的元素(如果有的话),肯定比我们选的当前高度要大,所以只有找到左边界才能计算正确的结果。
我们可以在原数组的两端分别加一个0,这样的话就相当于加了左右边界,可以遍历到所有的元素。(方法二)

方法一

public int largestRectangleArea1(int[] heights) {
        int res = 0;
        for(int i = 0; i < heights.length; i++){
            int leftBorder = i,rightBorder = i;
            for(; leftBorder >=0 && heights[leftBorder]>=heights[i]; leftBorder--);
            for(; rightBorder < heights.length && heights[rightBorder]>=heights[i]; rightBorder++);
            res = Math.max((rightBorder-leftBorder-1)*heights[i],res);
        }
        return res;
    }

方法二

public int largestRectangleArea(int[] heights){
        if(heights.length == 0) return 0;
        int[] real = new int[heights.length+2];
        for(int i = 1; i <= heights.length; i++) real[i] = heights[i-1];
        Stack<Integer> singleStack = new Stack<>();
        int res = 0;
        for(int rightBorder = 0; rightBorder < real.length; rightBorder++){
            while(!singleStack.isEmpty() && real[singleStack.peek()] > real[rightBorder]){
                int curIndex = singleStack.pop();
                int leftBorder = singleStack.peek();
                res = Math.max((rightBorder-leftBorder-1)*real[curIndex],res);
            }
            singleStack.push(rightBorder);
        }
        return res;
    }
发布了464 篇原创文章 · 获赞 21 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_41687289/article/details/105317820