LeetCode(84):柱状图中最大的矩形 Largest Rectangle in Histogram(Java)

2019.6.11 #程序员笔试必备# LeetCode 从零单刷个人笔记整理(持续更新)

这道hard智力题和之前刷过的炒股有点像。要想找到最大矩形面积,首先需要观察什么情况下能够构成一个局部最大的矩形。

对于高为h的矩形来说,其左边界left的高度必定大于left-1,右边界right的高度也必定大于right+1,且h是在left-right中最短的高。看透了这一点,我们就可以想办法来设计算法寻找并计算矩形。

方法一:左右扫描

以每一个柱子i的高度height[i]为矩形的高h,从i为中心向左右扫描找出left和right。

方法二:单调递增栈

借助辅助栈存储当前最大柱子高度对应的下标。当栈空或当前高度大于栈顶高度时,将元素入栈。

当柱子i小于栈顶元素p的高度时,i对应位置right+1,p的高度对应h,p在栈中的下一个元素s对应位置left-1。

通过这个方法还可以求区间最小值。

方法三:动态规划(最优)

建立数组lessFromLeft、lessFromRight。lessFromLeft[i]代表从i向左第一个高度小于i的元素的下标,也即对于i来说left的坐标;lessFromRight[i]代表从i向右第一个高度小于i的元素的下标,也即对于i来说right的坐标。利用动态规划的方法求解lessFromLeft、lessFromRight,再依次扫描求解矩形面积即可。


传送门:柱状图中最大的矩形

Given n non-negative integers representing the histogram’s bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.

Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].

The largest rectangle is shown in the shaded area, which has area = 10 unit.

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。求在该柱状图中,能够勾勒出来的矩形的最大面积。

以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。

图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。

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


import java.util.Stack;

/**
 *
 * Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.
 * 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。求在该柱状图中,能够勾勒出来的矩形的最大面积。
 *
 */

public class LargestRectangleInHistogram {
    //暴力法:以每一根柱子为中心向左右拓展获得最大区域
    public int largestRectangleArea(int[] heights) {
        int result = 0;
        for(int i = 0; i < heights.length; i++){
            int begin = i;
            while(begin >= 0 && heights[begin] >= heights[i]){
                --begin;
            }
            int end = i;
            while(end < heights.length && heights[end] >= heights[i]){
                ++end;
            }
            if(heights[i] * (end - begin - 1) > result){
                result = heights[i] * (end - begin - 1);
            }
        }
        return result;
    }

    //单调递增栈法:利用辅助栈动态存储当前最大高度柱子对应下标
    public int largestRectangleArea1(int[] heights){
        Stack<Integer> stack = new Stack<>();
        int maxArea = 0;
        for(int i = 0; i <= heights.length; i++){
            //最后一次扫描令柱子的高度为0,使栈中元素全部弹出
            int height = i == heights.length ? 0 : heights[i];
            //当栈空或当前高度大于栈顶高度时,将元素入栈。
            if(stack.empty() || height >= heights[stack.peek()]){
                stack.push(i);
            }
            //当当前高度小于栈顶高度时,可以计算并更新最大矩形面积。
            //由于栈顶元素t高度比p小,i也比p高度小。因此必能构成从t至i以i-t-1为底,height[p]为高的矩形。
            //若计算后当前高度依然小于栈顶高度,则继续计算。
            else{
                int curArea = heights[stack.pop()] * (stack.empty() ? i : i - stack.peek() - 1);
                maxArea = curArea > maxArea ? curArea : maxArea;
                --i;
            }
        }
        return maxArea;
    }

    //单调递增栈写法2
    public int largestRectangleArea11(int[] heights){
        Stack<Integer> stack = new Stack<>();
        stack.push(-1);
        int maxArea = 0;
        for(int i = 0; i < heights.length; i++){
            //弹出栈中所有不大于当前高度heights[i]的元素,计算矩形面积
            while(stack.peek() != -1 && heights[stack.peek()] >= heights[i]){
                maxArea = Math.max(maxArea, heights[stack.pop()] * (i - stack.peek() - 1));
            }
            stack.push(i);
        }
        //处理剩余栈中元素
        while(stack.peek() != -1){
            maxArea = Math.max(maxArea, heights[stack.pop()] * (heights.length - stack.peek() - 1));
        }
        return maxArea;
    }

    //记录每一个柱子在左扫描和右扫描下的最小高度
    public int largestRectangleArea2(int[] heights){
        if(heights.length == 0){
            return 0;
        }
        //lessFromLeft[i]代表从i向左第一个高度小于i的元素的下标
        //lessFromRight[i]代表从i向右第一个高度小于i的元素的下标
        int[] lessFromLeft = new int[heights.length];
        lessFromLeft[0] = -1;
        int[] lessFromRight = new int[heights.length];
        lessFromRight[heights.length - 1] = heights.length;

        for(int i = 1; i < heights.length; --i){
            int p = i - 1;
            while(p >= 0 && heights[p] >= heights[i]){
                p = lessFromLeft[p];
            }
            lessFromLeft[i] = p;
        }

        for(int i = heights.length - 2; i >= 0; --i){
            int p = i + 1;
            while(p >= 0 && heights[p] >= heights[i]){
                p = lessFromRight[p];
            }
            lessFromRight[i] = p;
        }

        int maxArea = 0;
        for(int i = 0; i < heights.length; ++i){
            //以lessFromRight[i] - lessFromLeft[i] - 1为底,heights[i]为高构成的矩形是以i为中心的最大矩形
            int curArea = heights[i] * (lessFromRight[i] - lessFromLeft[i] - 1);
            maxArea = curArea > maxArea ? curArea : maxArea;
        }
        return maxArea;
    }
}




#Coding一小时,Copying一秒钟。留个言点个赞呗,谢谢你#

你可能感兴趣的:(数据结构与算法,JAVA,LeetCode)