Leetcode 84 求直方圖中矩形的最大面積


題目描述

Leetcode 84 給定 n 個正整數的列表,表示矩形的高度,表示直方圖。每一個給出的矩形寬度是 1,找到在直方圖里最大的矩形面積。

img

如圖中給出的直方圖,寬度是 1,給出的高度是 [2,1,5,6,2,3].

可以在直方圖中找出最大的隱藏面積,答案是 10.

img

Input: [2,1,5,6,2,3]
Output: 10

題目分析

解法一:

最后矩形的最大面積,肯定是以某個矩形為最矮高度,向左向右可擴展的最大面積。

舉例子來說,假設以 6 為當前直方圖中的最矮高度,分別向左和向右擴展,但發現沒有找到比自己還高的。那么以 6 為最矮高度的矩形面積是 6.

如果以 2 以當前直方圖中的最矮高度,向左向右擴展后,發現左面高度為5, 6 的矩形和右面為 3 的矩形,都比自己高。那么以 2 為最矮高度的矩形面積是 2 + 2+ 2 + 2 = 8.

所以,依次以每個位置的矩形為最矮位置,然后依次拓展就能找到最大的矩形面積了。

class Solution:
    def largestRectangleArea_old(self, heights: List[int]) -> int:
        """
        O(n^2) -> 超時了,無法提交成功
        :param heights:
        :return:

         思路:最后形成最大的矩形面積,肯定是以給定的數組中某個位置連續矩形的最矮位置。
         從 index=0 的位置開始,假定它是這樣的位置,然后向左向右開始掃描,找出其連續的矩形
         面積,然后依次比較這些找到的矩形面積。
        """
        max_area = 0
        index = 0
        list_length = len(heights)
        while index < list_length:
            area = heights[index]
            left_index = index - 1
            while left_index > -1:
                if heights[left_index] >= heights[index]:
                    area += heights[index]
                    left_index -= 1
                else:
                    break

            right_index = index + 1
            while right_index < list_length:
                if heights[right_index] >= heights[index]:
                    area += heights[index]
                    right_index += 1
                else:
                    break
            max_area = max_area if max_area > area else area
            index += 1

        return max_area

但可以發現,依次遍歷每個矩形的位置,時間復雜度為 O(n^2).

解法二:

如解法 1 提到的,最大的矩形面積其實就是以某個矩形為最矮位置可擴展的最大面積。這里使用的數據結構是單調遞增棧,用於保存局部矩形的峰值。

單調棧就是在棧里的元素,按照一定的規則進行排序。在本題里,棧里記錄的是給定的矩形高度的位置。依次去循環 heights 里的元素,如果比棧頂的元素的大,那么就將元素入棧。如果比棧頂元素的小,就需要出棧,計算以當前棧頂元素形成的矩形面積,直到遇到和要入棧元素一樣高的位置再停止。

需要注意的地方是:

  • 給定的元素可能是一直遞增的,所以需要給 heights 末尾添加一個元素 0,用於計算之前的面積。
  • 需要考慮出棧后,站內元素為 0 的情況,這時需要計算,最低矩形高度可以形成的連續矩形面積的情況。例如 [2,1,2] 這種情況。
class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        # add 0 to query the last local peak area
        # if the last height is still the highest
        heights.append(0)
        # definite a stack to record the heights position
        # to get the local peak area
        heights_position = []
        max_area = 0
        #
        index = 0
        while index < len(heights):
            if len(heights_position) == 0 or heights[heights_position[-1]] <= heights[index]:
                heights_position.append(index)
                index += 1
            else:
                popped_position = heights_position.pop()
                # get the continuous area of the smallest rectangle
                # index represents the the number of elements has been processed
                if len(heights_position) == 0:
                    max_area = max(max_area, index * heights[popped_position])
                # Get maximum area of rectangle in monotonically increasing
                else:
                    # index need to reduce 1 because the we add a 0
                    #  to the end of heights array.
                    max_area = max(max_area,
                                   (index - 1 - heights_position[-1]) * heights[popped_position])
        return max_area

對於解法 2 來說,每個元素最多會入棧和出棧一次,所以時間復雜度為 O(2n) 也就是 O(n).


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM