题目如下:

1.暴力求解
面积 = 底 * 高:
1.固定底,求最大高度;
2.固定高,求最长底边。采用双指针从中间指针向两边扩散,直到找到严格小于中间指针所对应的高度。
- 如果我们枚举「宽」,我们可以使用两重循环枚举矩形的左右边界以固定宽度,此时矩形的高度就是所有包含在内的柱子的「最小高度」,代码如下:
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
n = len(heights)
res = 0
for i in range(n):
for j in range(i, n):
res = max(res, ((j - i + 1) * min(heights[i:j+1])))
return res
- 如果我们枚举「高」,我们可以使用一重循环枚举某一根柱子,将其固定为矩形的高度h。随后我们从这跟柱子开始向两侧延伸,直到遇到高度小于h的柱子,就确定了矩形的左右边界。代码如下:
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
n = len(heights)
res = 0
for i in range(n):
l, r = i, i
current = heights[i]
while l >= 0 and heights[l] >= current:
l -= 1
while r <= n - 1 and heights[r] >= current :
r += 1
res= max(res, (r - l - 1) * current)
return res
暴力求解的时间复杂度为O(n2)。考虑到枚举「宽」的方法使用了两重循环,本身就已经需要 O(N2)的时间复杂度,不容易优化,因此我们可以考虑优化只使用了一重循环的枚举「高」的方法。
空间换时间,因此可以得到的数据结构是栈。
2.单调栈
将数组的索引入栈,当当前索引对应的数值小于栈顶索引对应的数值时,栈顶元素出栈,可以确定该索引对应下的数值下的最大面积。
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
n = len(heights)
stack = []
res = 0
for i in range(n):
while stack and heights[i] < heights[stack[-1]]:
cur_h = heights[stack.pop()]
while stack and cur_h == heights[stack[-1]]:
stack.pop()
if stack:
cur_w = i - stack[-1] - 1
else:
cur_w = i
res = max(res, cur_h * cur_w)
stack.append(i)
while stack:
cur_h = heights[stack.pop()]
while stack and cur_h == heights[stack[-1]]:
stack.pop()
if stack:
cur_w = n - stack[-1] - 1
else:
cur_w = n
res = max(res, cur_h * cur_w)
return res
时间复杂度O(N):输入数组里的每一个元素入栈一次,出栈一次;
空间复杂度O(N):栈的空间最大为数组的长度。
3.单调栈+常数优化
在方法2中,我们遍历完N次循环后,还进行了一次栈空间元素排查,是否还存在索引值,这是因为经历N次循环后,入栈的元素并不一定能够全部出栈,因此,如果我们在数组的开头和结尾各加一个很小的数(如0),则N次循环后,栈可以变为空。该两头添加元素的方法称为哨兵方法。另外,如果有连续的数值相等,在方法2中进行了一个while循环进行连续出栈操作,实际上不进行该操作,结果也正确。
优化的代码如下:
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
heights = [0] + heights + [0] #在数组两头各加入一个哨兵0
n = len(heights)
stack = [0] #将数组头的哨兵入栈,因此栈可以不用做非空判断
res = 0
for i in range(1, n):
while heights[i] < heights[stack[-1]]:
cur_h = heights[stack.pop()]
cur_w = i - stack[-1] - 1
res = max(res, cur_h * cur_w)
stack.append(i)
return res