[Leedcode][JAVA][第84题][柱状图中最大的矩形][暴力][单调栈]

【问题描述】[困难]

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

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

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

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

来源:力扣(LeetCode)


[Leedcode][JAVA][第84题][柱状图中最大的矩形][暴力][单调栈]_第1张图片

【解答思路】

1. 暴力

可以枚举以每个柱形为高度的最大矩形的面积。

具体来说就是:依次遍历柱形的高度,对于每一个高度分别向两边扩散,求出以当前高度为矩形的最大宽度多少。
[Leedcode][JAVA][第84题][柱状图中最大的矩形][暴力][单调栈]_第2张图片
时间复杂度:O(N^2) 空间复杂度:O(1)

public class Solution {

    public int largestRectangleArea(int[] heights) {
        int len = heights.length;
        // 特判
        if (len == 0) {
            return 0;
        }

        int res = 0;
        for (int i = 0; i < len; i++) {

            // 找左边最后 1 个大于等于 heights[i] 的下标
            int left = i;
            int curHeight = heights[i];
            while (left > 0 && heights[left - 1] >= curHeight) {
                left--;
            }

            // 找右边最后 1 个大于等于 heights[i] 的索引
            int right = i;
            while (right < len - 1 && heights[right + 1] >= curHeight) {
                right++;
            }

            int width = right - left + 1;
            res = Math.max(res, width * curHeight);
        }
        return res;
    }
}




2. 单调栈

[Leedcode][JAVA][第84题][柱状图中最大的矩形][暴力][单调栈]_第3张图片
[Leedcode][JAVA][第84题][柱状图中最大的矩形][暴力][单调栈]_第4张图片
[Leedcode][JAVA][第84题][柱状图中最大的矩形][暴力][单调栈]_第5张图片[Leedcode][JAVA][第84题][柱状图中最大的矩形][暴力][单调栈]_第6张图片
时间复杂度:O(N) 空间复杂度:O(N)

import java.util.ArrayDeque;
import java.util.Deque;

public class Solution {

    public int largestRectangleArea(int[] heights) {
        int len = heights.length;
        if (len == 0) {
            return 0;
        }
        if (len == 1) {
            return heights[0];
        }

        int area = 0;
        Deque<Integer> stack = new ArrayDeque<>();
        for (int i = 0; i < len; i++) {
            while (!stack.isEmpty() && heights[stack.peekLast()] > heights[i]){
                int height = heights[stack.removeLast()];

                while (!stack.isEmpty() &&  heights[stack.peekLast()] == height){
                    stack.removeLast();
                }

                int width;
                if (stack.isEmpty()){
                //i
                    width = i;
                } else {
                    width = i - stack.peekLast() - 1;
                }

                area = Math.max(area , width * height);
            }
            stack.addLast(i);
        }
//遍历完还没出栈的
        while (!stack.isEmpty()){
            int height = heights[stack.removeLast()];

            while (!stack.isEmpty() &&  heights[stack.peekLast()] == height){
                stack.removeLast();
            }

            int width;
            if (stack.isEmpty()){
                width = len;//肯定能到达
            } else {
                width = len - stack.peekLast() - 1;
            }

            area = Math.max(area , width * height);
        }
        return area;
    }
}
3. 哨兵思想+单调栈

[Leedcode][JAVA][第84题][柱状图中最大的矩形][暴力][单调栈]_第7张图片

[Leedcode][JAVA][第84题][柱状图中最大的矩形][暴力][单调栈]_第8张图片
时间复杂度:O(N) 空间复杂度:O(N)

import java.util.ArrayDeque;
import java.util.Deque;

public class Solution {

    public int largestRectangleArea(int[] heights) {
        int len = heights.length;
        if (len == 0) {
            return 0;
        }
        if (len == 1) {
            return heights[0];
        }

        int area = 0;
        int[] newHeights = new int[len + 2];
        for (int i = 0; i < len; i++) {
            newHeights[i + 1] = heights[i];
        }
        len += 2;
        heights = newHeights;

        Deque<Integer> stack = new ArrayDeque<>();
        stack.addLast(0);

        for (int i = 1; i < len; i++) {
            while (heights[stack.peekLast()] > heights[i]) {
                int height = heights[stack.removeLast()];
                int width  = i - stack.peekLast() - 1;
                area = Math.max(area, width * height);
            }
            stack.addLast(i);
        }
        return area;
    }
}

【总结】

1.算法思想

其实可以把这个想象成锯木板,如果木板都是递增的那我很开心,如果突然遇到一块木板i矮了一截,那我就先找之前最戳出来的一块(其实就是第i-1块),计算一下这个木板单独的面积,然后把它锯成次高的,这是因为我之后的计算都再也用不着这块木板本身的高度了。再然后如果发觉次高的仍然比现在这个i木板高,那我继续单独计算这个次高木板的面积(应该是第i-1和i-2块),再把它俩锯短。直到发觉不需要锯就比第i块矮了,那我继续开开心心往右找更高的。当然为了避免到了最后一直都是递增的,所以可以在最后加一块高度为0的木板

这个算法的关键点是把那些戳出来的木板早点单独拎出来计算,然后就用不着这个值了。

2.对于 使用 Java 的朋友, Stack 改用 Deque 的问题,参考文章:https://mp.weixin.qq.com/s/Ba8jrULf8NJbENK6WGrVWg
3.单调栈

出栈都要做的判断!stack.isEmpty()
[Leedcode][JAVA][第84题][柱状图中最大的矩形][暴力][单调栈]_第9张图片

4.哨兵思想

[Leedcode][JAVA][第84题][柱状图中最大的矩形][暴力][单调栈]_第10张图片

转载链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram/solution/bao-li-jie-fa-zhan-by-liweiwei1419/

参考链接:
https://leetcode-cn.com/problems/largest-rectangle-in-histogram/solution/xiang-jie-dan-diao-zhan-bi-xu-miao-dong-by-sweetie/

你可能感兴趣的:(刷题,非0即1)