leetcde-------求柱狀圖中最大的矩形(動態規劃,中心擴展)

解法一:暴力枚舉法:

思路:枚舉出,每一列對應的最大矩形。最後找出最大的那個即可。

首先,要想找到第 i 位置最大面積是什麼?

是以i 爲中心,向左找第一個小於 heights[i] 的位置 left_i;向右找第一個小於於 heights[i] 的位置 right_i,即最大面積爲 heights[i] * (right_i - left_i -1),如下圖所示:

代碼:

class Solution:
    def largestRectangleArea(self, heights: list) -> int:
        max_area = 0
        for i in range(len(heights)):
            left_i = i
            right_i = i
            while left_i >= 0 and heights[left_i] >= heights[i]:
                left_i -= 1
            while right_i < len(heights) and heights[right_i] >= heights[i]:
                right_i +=1
            area = heights[i]*(right_i-left_i-1)
            max_area = max(max_area,area)
            print('a={},i={},left={}.right={}'.format(area,i,left_i,right_i))
        return max_area

ss = Solution()
print(ss.largestRectangleArea([2,1,5,6,2,3]))  #10

時間複雜度:O(n^2)

空間複雜度:O(1)

 

解法二:暴力+動態規劃(動態規劃最小值求解)

爲什麼說是暴力法,因爲這個解法也是要羅列出所有 i 位置矩形面積,從中選最大的。只是加入了動態規劃的思想。

假設 dp[i][j]爲位置從 i~j 的最小高度。則有:

dp[i][j]=min(height[j],dp[i][j-1])

代碼一共兩個循環,第一個循環,變量 i 取值0~n(n爲輸入列表的大小)。第二個循環,變量 j 取值 i~n。

依次計算矩陣(i~j)的面積。面積 = dp[i][j] * (j-i+1)

代碼:

class Solution:
    def largestRectangleArea(self, heights: [int]) -> int:
        n = len(heights)
        max_area = 0
        dp = [[0 for i in range(n)] for j in range(n)]  #一般來說,沒經過空間 優化的動態規劃都會具備這麼一個二維矩陣
        for i in range(n):
            for j in range(i,n):
                if i == j:
                    dp[i][j] = heights[i]
                elif heights[j] < dp[i][j-1]:
                    dp[i][j] = heights[j]
                elif heights[j] >= dp[i][j-1]:
                    dp[i][j] = dp[i][j-1]
                area = dp[i][j]*(j-i+1)
                max_area = max(max_area,area)
        return max_area
ss = Solution()
print(ss.largestRectangleArea([2,1,5,6,2,3]))  #10

時間複雜度:O(n^2)

空間複雜度:O(n^2)  因爲數組 dp大小爲 n*n
 

三,空間 優化後的動態規劃

從解法二中我們可以看到,數組dp佔的位置很多,而且dp中的值一般只被使用一次。所以dp可以用一個不斷更新的變量代替。

class Solution:
    def largestRectangleArea(self, heights: [int]) -> int:
        n = len(heights)
        max_area = 0
        max_height = 0
        for i in range(n):
            for j in range(i,n):
                if i == j:
                    max_height = heights[i]
                elif heights[j] < max_height:
                    max_height = heights[j]
                area = max_height*(j-i+1)
                max_area = max(max_area,area)
        return max_area
ss = Solution()
print(ss.largestRectangleArea([2,1,5,6,2,3]))  #10

時間複雜度:O(n^2)

空間複雜度:O(1)

 

解法三,中心擴展法

對於每個柱子,考慮以當前柱高h作爲矩形中的最大高度來構建矩陣。如果臨近的柱子柱高比h更大,那麼矩形可以向外側擴展。

例如對於[4,2,3], i=2時,由於h[0] < h[1] > h[2],那麼其左右端點可以延伸到left=0, right=2,即底長爲2-0+1 = 3。
對於[4,2,1],i=2時,由於h[0] < h[1] , h[2] > h[0],那麼左右端點爲left=0, right=1,底長爲1-0+1 = 2。

class Solution:
    def largestRectangleArea(self, heights: [int]) -> int:
        n = len(heights)
        max_area = 0
        for i in range(n):
            left = i
            right = i
            while left >0 and heights[left]>=heights[i]:
                left -= 1
            while right < n and heights[right]>=heights[i]:
                right +=1
            area = heights[i]*(right-left-1)
            max_area = max(max_area,area)
        return max_area
ss = Solution()
print(ss.largestRectangleArea([2,1,5,6,2,3]))  #10

時間複雜度:O(n^2)

空間複雜度:O(1)

 

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