给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
示例 1:
输入:heights = [2,1,5,6,2,3] 输出:10 解释:最大的矩形为图中红色区域,面积为 10
示例 2:
输入: heights = [2,4] 输出: 4
解题思路:
暴力解法
以当前柱子的高度,查找可以组成的最大矩形的问题
向左查找第一个低于当前柱子高度的柱子,向右查找第一个低于当前高度的柱子,该区间的所有柱子的高度都大于/等于该柱子,所以可以组成的最大面积=该区间的宽度*该柱子的高度;
如果左边
首先,要想找到第 i 位置最大面积是什么?
是以i 为中心,向左找第一个小于 heights[i] 的位置 left_i;向右找第一个小于于 heights[i] 的位置 right_i,即最大面积为 heights[i] * (right_i - left_i -1),如下图所示:
所以,我们的问题就变成如何找 right_i 和 left_i?
最简单的思路就是,就是暴力法,直接分别在 i 左右移动。
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
res = 0
n = len(heights)
for i in range(n):
left_i = i
right_i = i
while left_i >= 0 and heights[left_i] >= heights[i]:
left_i -= 1
while right_i < n and heights[right_i] >= heights[i]:
right_i += 1
res = max(res, (right_i - left_i - 1) * heights[i])
return res
但是,这是一个时间复杂度为 O(n^2),超时。
也可以进行优化:
当我们找 i 左边第一个小于 heights[i] 如果 heights[i-1] >= heights[i] 其实就是和 heights[i-1] 左边第一个小于 heights[i-1] 一样。依次类推,右边同理。
用两个数组分别记录每个柱子的左侧第一个小于该柱子高度的柱子,右侧第一个小于该柱子高度的柱子,查找左边界时,如果左侧的柱子高度大于该柱子,则直接查找左侧柱子的第一个小于左侧柱子高度的柱子,依次查找,直到查找到低于该柱子的柱子为左边界,右侧的类似。
代码:
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
if not heights:
return 0
n = len(heights)
left_i = [0] * n
right_i = [0] * n
left_i[0] = -1
right_i[-1] = n
for i in range(1, n):
tmp = i - 1
while tmp >= 0 and heights[tmp] >= heights[i]:
tmp = left_i[tmp]
left_i[i] = tmp
for i in range(n - 2, -1, -1):
tmp = i + 1
while tmp < n and heights[tmp] >= heights[i]:
tmp = right_i[tmp]
right_i[i] = tmp
# print(left_i)
# print(right_i)
res = 0
for i in range(n):
res = max(res, (right_i[i] - left_i[i] - 1) * heights[i])
return res
优化思路
单调栈:首先确定右边界(即,一个柱子的高度小于它左侧的柱子的高度,为最大矩形的右侧边界),逐渐查找前端可以以该柱子当做右侧边界的柱子(柱子的高度需大于该边界的柱子高度)可以组成的最大矩形
维护一个单调递增的栈,就可以找到 left_i 和 right_i。
代码:
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
stack = []
heights = [0] + heights + [0]
res = 0
for i in range(len(heights)):
#print(stack)
while stack and heights[stack[-1]] > heights[i]:
tmp = stack.pop()
res = max(res, (i - stack[-1] - 1) * heights[tmp])
stack.append(i)
return res