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;
    }
}

棧 單調棧

在這裏插入圖片描述

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