解法一:暴力枚舉法:
思路:枚舉出,每一列對應的最大矩形。最後找出最大的那個即可。
首先,要想找到第 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)