1. 程式人生 > 其它 >【LeetCode】84. 柱狀圖中最大的矩形

【LeetCode】84. 柱狀圖中最大的矩形

84. 柱狀圖中最大的矩形

知識點:單調棧

題目描述

給定 n 個非負整數,用來表示柱狀圖中各個柱子的高度。每個柱子彼此相鄰,且寬度為 1 。

求在該柱狀圖中,能夠勾勒出來的矩形的最大面積。

示例
輸入:heights = [2,1,5,6,2,3]
輸出:10
解釋:最大的矩形為圖中紅色區域,面積為 10(以5為高的)

輸入: heights = [2,4]
輸出: 4

解法一:暴力法

以每個元素為中心向左右擴散,這個元素就是這個高度。

暴力法
class Resolution:
    def get_biggest(self, heights):
        max_area = 0
        for i, height in enumerate(heights):
            p, q = i+1, i-1
            while p < len(heights) and heights[p] >= height:
                p += 1
            while q >= 0 and heights[q] >= height:
                q -= 1
            area = height * (p-q-1)
            max_area = max(max_area, area)
        return max_area
r = Resolution()

解法二:單調棧

上面的解法需要去尋找每個元素它左右兩邊第一個比它小的元素下標,這時候就可以確定寬度進而確定面積了。第一個比它大或者小的,這不就是可以用單調棧嗎?
可以維持一個單調遞增棧,if遇到更大的元素,那以它為高的矩形還不能確定,當遇到小的時候,對於棧頂元素而言,棧的下一個元素比其小,要入棧的比其小,所以矩形就確定了。
想一下棧裡應該存什麼,求面積無非就是寬乘以高,if存高度,那寬度就沒有辦法確定,但是if是存下標,那寬度和高度都可以確定。
對於單調棧的問題,重點是要弄清楚當元素出棧的時候,意味著什麼。比如尋找一個數組裡第一個比它大的元素,那就可以維持一個單調遞減棧。當遇到大的元素時,出棧。這時候出棧就意味著找到了第一個比自己大的元素;對於這個題,出棧就意味著確定了以它為高的矩陣。

  • 未優化
class Resolution:
    def get_biggest(self, heights):
        max_area = 0
        stack = []
        for i, height in enumerate(heights):
            while stack and height < heights[stack[-1]]:
                cur_height = heights[stack.pop()]
                while stack and cur_height == heights[stack[-1]]: #可能存在相同的值;
                    stack.pop()
                if stack:   #棧為空和非空不一樣
                    width = i - stack[-1] - 1
                else:
                    width = i
                area = cur_height * width
                max_area = max(max_area, area)
            stack.append(i)
        while stack:  # 仍然在棧裡的元素;
            cur_height = heights[stack.pop()]
            while stack and cur_height == heights[stack[-1]]:
                stack.pop()
            if stack:
                width = len(heights) - stack[-1] - 1
            else:
                width = len(heights)
            max_area = max(max_area, cur_height * width)
        return max_area
  • 優化
    在首尾各加一個高度為0,這時候就不用單獨判斷了,因為任何值都會比0大,所以都會入棧,又因為任何值都比0大,所以都會出棧;
class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        size = len(heights)
        res = 0
        heights = [0] + heights + [0]
        # 先放入哨兵結點,在迴圈中就不用做非空判斷
        stack = [0]
        size += 2

        for i in range(1, size):
            while heights[i] < heights[stack[-1]]:
                cur_height = heights[stack.pop()]
                cur_width = i - stack[-1] - 1
                res = max(res, cur_height * cur_width)
            stack.append(i)
        return res

相關連結

題解