1. 程式人生 > >LeetCode84柱狀圖中最大的矩形

LeetCode84柱狀圖中最大的矩形

題目描述:

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

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

以上是柱狀圖的示例,其中每個柱子的寬度為 1,給定的高度為 [2,1,5,6,2,3]

圖中陰影部分為所能勾勒出的最大矩形面積,其面積為 10 個單位。

示例:

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

解題思路:

思路一:

這個方法是一個超時的方法。

因為要求所能圍成的矩形的最大面積,而所圍成的矩形的高度,肯定是來自於列表中矩形的高度。所以只需要求得不同高度的矩形所能圍成的最大矩形面積即可。

需要使用兩次遍歷,外層遍歷是使用的矩形的高度,內層是對所有矩形進行遍歷,求得使用當前高度所能圍成的矩形的面積。使用上例,當前高度為2時,當前高度所能圍成的矩形有兩個,如下圖:

每次計算均需重複遍歷一遍列表,演算法的複雜度為 O ( n 2 )

O(n^2)

程式碼實現為:

def largestRectangleArea(heights):
    """
    :type heights: List[int]
    :rtype: int
    """
    if len(heights) == 0:
        return 0

    h = max(heights)
    s = min(heights)
    ans = 0

    for i in range(s, h + 1):
        start =
end = 0 flag = False for j in range(len(heights)): if heights[j] >= i: end = j + 1 flag = True else: if flag: temp = (end - start) * i if temp > ans: ans = temp start = j + 1 flag = False else: start = j + 1 flag = False if j == len(heights)-1 and flag: temp = (end - start) * i if temp > ans: ans = temp return ans

思路二:

這是一個正確的方法,演算法的複雜度為 O ( n ) O(n)

需要遍歷一次陣列,使用棧來操作已經遍歷過的矩形。棧中儲存的是遍歷過的資料的索引值,而非資料值。

入棧及出棧規則如下:

  1. 當棧為空時,入棧
  2. 當棧頂元素小於當前值時,當前值入棧
  3. 當棧頂元素不小於當前值時,棧頂元素出棧,此時計算當前出棧元素的高,所能圍成的最大矩形。
  4. 再次比較棧頂元素與當前值的大小

面積計算規則為:出棧元素高度 * (當前值索引 - (出棧後,棧內top元素索引) - 1) ,如下示意圖:

當遍歷到index=4時,此時棧中儲存著[1, 2, 3],此時heights[4] < heights[3],所以要出棧,計算以heights[3]所能圍成的最大面積:(4 - 2 - 1) * heights[3]。

此時棧頂元素的值 heights[2] > heights[4],所以要繼續出棧,面積:(4 - 2 - 1) * heights[2],注意處理邊界情況,即當出棧之後棧為空時。

繼續:

當遍歷一遍之後,此時棧中還儲存有一系列有序的元素,以這題為例,剩餘結果如下:

因為是一個有序的列表,在其後的高度,都是高於之前的,這點要理解。

從頭到尾遍歷,所能圍成的面積即為,當前高度 heights[index] * (當前索引到末尾元素的索引差)

經過以上計算方法,最後得到的最大值,即為所能圍成的最大矩形面積。

程式碼實現:

Python實現,GitHub地址為:https://github.com/zhangdianlei/LeetCode_python/blob/master/src/c84.py

def largestRectangleArea(heights):
    """
    :type heights: List[int]
    :rtype: int
    """
    arr = []
    ans = 0
    for index, item in enumerate(heights):

        if len(arr) == 0:
            arr.insert(0, index)
            continue

        if item > heights[arr[0]]:
            arr.insert(0, index)
        else:
            while heights[arr[0]] >= item:
                top = arr.pop(0)
                if len(arr) == 0:
                    temp = index * heights[top]
                else:
                    temp = (index - arr[0] - 1) * heights[top]

                if temp > ans:
                    ans = temp
                if len(arr) == 0:
                    break

            arr.insert(0, index)

    if len(arr) > 0:
        last = arr[0]

        while len(arr) > 0:
            top = arr.pop(0)

            if len(arr) > 0:
                temp = (last - arr[0]) * heights[top]
                if temp > ans:
                    ans = temp
            else:
                temp = (last + 1) * heights[top]
                if temp > ans:
                    ans = temp

    return ans