leetcode **84. 柱状图中最大的矩形(单调栈题目表)

【题目】**84. 柱状图中最大的矩形

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
在这里插入图片描述
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。
在这里插入图片描述
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。

示例:

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

【解题思路1】暴力法

在这里插入图片描述


【解题思路2】单调栈

在这里插入图片描述
遍历到下标4的时候,可以确定高度为6的宽度最多为1,然后也可以确定高度为5的宽度最多为2,先确定了3位置对应高度的宽度,然后确定2位置对应高度的宽度,符合先进后出的规律

  • 入栈一个元素高度,表示这个高度还无法确定其宽度
  • 出栈一个元素高度,表示可以确定这个高度的宽度了
  • 出栈条件,遍历到的元素高度严格小于当前栈顶元素高度,栈顶元素出栈,顺便计算出栈顶元素高度能勾勒出的矩形的宽度和面积
  • 矩形宽度 = 当前遍历到的下标 - 出栈以后的新栈顶下标 - 1

在这里插入图片描述
在这里插入图片描述
可以假象最右边有个高度为0的柱形其小标为6,所小标4对应的高度为2的柱形可以一直扩散到末尾
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
遇到新栈顶和当前栈顶高度相同的情况,弹出当前的栈顶直接跳过,不计算面积
但也可以不做特殊处理,因为在计算新栈顶的时候会把不准确的结果替换掉
在这里插入图片描述
哨兵1可以省去栈非空判断
哨兵2可以保证所有元素都出栈(除了哨兵1这个高度为0的),可以省去遍历完之后再将栈内剩余元素出栈的步骤
在这里插入图片描述
在这里插入图片描述

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;
        Stack<Integer> stack = new Stack<>();
        for(int i = 0; i < len; i++){
            //当栈顶元素高度大于当前遍历到的元素高度
            while(!stack.isEmpty() && heights[stack.peek()] > heights[i]){
                int height = heights[stack.pop()];
                //处理栈顶和新栈顶元素值相同的情况,可以省去这步
                while(!stack.isEmpty() && heights[stack.peek()] == height){
                    stack.pop(); 
                }
                int width;
                if(stack.isEmpty()){
                    width = i; //栈空,说明从开头到当前位置都可以构成高度为height的矩形
                }else{
                    width = i - stack.peek() - 1;
                }
                area = Math.max(area, width * height);
            }
            stack.push(i);
        }

        //栈中剩余元素依次出栈,逻辑和上面完全一样
        while(!stack.isEmpty()){
            int height = heights[stack.pop()];
            //处理栈顶和新栈顶元素值相同的情况,可以省去这步
            while(!stack.isEmpty() && heights[stack.peek()] == height){
                stack.pop(); 
            }
            int width;
            //注意这里直到len都可以构成height高度的矩形,不受下一个heights[i]约束
            if(stack.isEmpty()){
                width = len;
            }else{
                width = len - stack.peek() - 1;
            }
            area = Math.max(area, width * height);
        }
        
        return area;
    }
}

设置哨兵精简后的代码

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; //这样写的话,下面的逻辑里面的数组名就不需要更新了

        Stack<Integer> stack = new Stack<>();
        stack.push(0);
        for(int i = 0; i < len; i++){
            //当栈顶元素高度大于当前遍历到的元素高度
            while(heights[stack.peek()] > heights[i]){
                int height = heights[stack.pop()];
                int width = i - stack.peek() - 1;
                area = Math.max(area, width * height);
            }
            stack.push(i);
        }
        
        return area;
    }
}

栈 单调栈

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章