Largest Rectangle in Histogram

Problem

Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.
histogram
Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].
histogram-area
The largest rectangle is shown in the shaded area, which has area = 10 unit.算法

For example,
Given height = [2,1,5,6,2,3],
return 10.app

Solution

暴力窮舉法

最簡單的天然是暴力法,即窮舉左端座標和右端座標,計算兩個座標之間矩形的最大面積,再從全部的面積中得出最大的即爲解。可是該方法至少須要兩個for循環來遍歷每一種左右端的組合,時間複雜度爲O($n^2$)。如下是該方法的代碼,解是對的,但在leetcode上會超時。spa

class Solution:
    # @param height, a list of integer
    # @return an integer
    def largestRectangleArea(self, height):
        length = len(height)
        max_area = -1
        for i in range(length):
            for j in range(i + 1, length):
                h = min(height[i: j])
                area = h * (j - i)
                if max_area < area:
                    max_area = area
        return max_area
利用棧減少時間複雜度

能夠考慮,計算一個矩形的面積時,好比圖
histogram-area
中的斜線部分,其兩側的高度必定是低於矩形所在的矩形條的高度的,所以能夠經過維護一個棧來得出左端左邊及右端座標和矩形的高度,每個矩形條只進棧一次,這樣時間複雜度爲O(n)。
1. 算法從左向右遍歷每一個矩形,以當前遍歷的位置爲右端座標,若是棧爲空或者當前矩形不低於棧頂的矩形,則將當前的位置座標壓棧,由於此時的座標必定不是右邊界(指要計算的面積右邊的一個矩形條,不包含在要計算的面積中),例如圖中,加入當前座標爲3,高度爲6,棧頂座標的高度爲5,那麼當前矩形條不可能做爲右邊界,將其壓棧。
2. 若是當前位置的矩形低於棧頂的矩形條,那麼當前位置能夠做爲一個矩形的邊界,則從這個位置開始向左遍歷,對每一個高度大於右邊界的矩形條做爲左邊界計算一次面積,直到高度小於右邊界或棧爲空。
3. 在遍歷過一遍以後,若是棧不爲空,則以棧中的每一個座標做爲左邊界計算一次面積,結合步驟2得出最大面積。
Accepted code以下:code

class Solution:
    # @param height, a list of integer
    # @return an integer
    def largestRectangleArea(self, height):
        max_area = 0
        i = 0
        n = len(height)
        stack = []
        while i < n:
            if len(stack) == 0 or height[i] >= height[stack[-1]]:
                stack.append(i)
                i += 1
            else:
                top = stack.pop()
                area_with_top = height[top] * (i if len(stack) == 0 else i - stack[-1] - 1)
                if max_area < area_with_top:
                    max_area = area_with_top

        while len(stack) != 0:
            top = stack.pop()
            area_with_top = height[top] * (i if len(stack) == 0 else i - stack[-1] - 1)
            if max_area < area_with_top:
                max_area = area_with_top

        return max_area

這個方法並非提供一個準確的找出最大的矩形的算法,而是經過試驗那些「可能」成爲最大的矩形的面積,再從其中找出最大的。而最大的矩形必定知足兩個邊界的高度小於該矩形的高度這個條件(若是不知足的話,邊界也能夠被添加進來計算而不破壞矩形的形狀,此時不爲最大),所以找出全部這樣的矩形就必定能夠在其中找出面積最大的矩形。leetcode

相關文章
相關標籤/搜索