解法一:暴力枚举法:
思路:枚举出,每一列对应的最大矩形。最后找出最大的那个即可。
首先,要想找到第 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)