小S最近在分析一个数组 ℎ1,ℎ2,...,ℎ𝑁,数组的每个元素代表某种高度。小S对这些高度感兴趣的是,当我们选取任意 𝑘k 个相邻元素时,如何计算它们所能形成的最大矩形面积。
对于 𝑘 个相邻的元素,我们定义其矩形的最大面积为:
𝑅(𝑘)=𝑘×𝑚𝑖𝑛(ℎ[𝑖],ℎ[𝑖+1],...,ℎ[𝑖+𝑘−1])
即,𝑅(𝑘)的值为这 𝑘个相邻元素中的最小值乘以 𝑘。现在,小S希望你能帮他找出对于任意 𝑘,𝑅(𝑘) 的最大值。
为了计算给定数组中任意 kk 个相邻元素所能形成的最大矩形面积,我们可以使用单调栈(Monotonic Stack)来高效地解决这个问题。单调栈可以帮助我们在 O(n)O(n) 时间复杂度内找到每个元素左边和右边第一个比它小的元素的位置,从而快速计算出每个元素作为最小值时所能形成的矩形面积。
实现思路
- 预处理:使用单调栈预处理每个元素左边和右边第一个比它小的元素的位置。
- 计算最大矩形面积:对于每个元素,计算以该元素为最小值时所能形成的矩形面积,并更新最大值。
详细步骤
-
初始化:
- 创建两个数组
left和right,分别存储每个元素左边和右边第一个比它小的元素的位置。 - 初始化
left数组为 -1,表示左边没有比它小的元素。 - 初始化
right数组为 n,表示右边没有比它小的元素。
- 创建两个数组
-
单调栈预处理:
- 使用单调递增栈从左到右遍历数组,计算
left数组。 - 使用单调递增栈从右到左遍历数组,计算
right数组。
- 使用单调递增栈从左到右遍历数组,计算
-
计算最大矩形面积:
- 对于每个元素
h[i],计算以h[i]为最小值时的矩形面积area = h[i] * (right[i] - left[i] - 1)。 - 更新最大矩形面积。
- 对于每个元素
实现代码
def solution(heights):
n = len(heights)
left = [-1] * n
right = [n] * n
# 单调栈计算 left 数组
stack = []
for i in range(n):
while stack and heights[stack[-1]] >= heights[i]:
stack.pop()
if stack:
left[i] = stack[-1]
stack.append(i)
# 单调栈计算 right 数组
stack = []
for i in range(n - 1, -1, -1):
while stack and heights[stack[-1]] >= heights[i]:
stack.pop()
if stack:
right[i] = stack[-1]
stack.append(i)
# 计算最大矩形面积
max_area = 0
for i in range(n):
area = heights[i] * (right[i] - left[i] - 1)
max_area = max(max_area, area)
return max_area
# 测试样例
print(solution([1, 2, 3, 4, 5])) # 输出: 9
print(solution([5, 4, 3, 2, 1, 6])) # 输出: 9
print(solution([4, 4, 4, 4])) # 输出: 16
代码解释
-
初始化:
left和right数组分别初始化为 -1 和 n,表示默认值。stack用于单调栈的实现。
-
单调栈预处理:
- 计算
left数组:从左到右遍历数组,使用单调递增栈找到每个元素左边第一个比它小的元素的位置。 - 计算
right数组:从右到左遍历数组,使用单调递增栈找到每个元素右边第一个比它小的元素的位置。
- 计算
-
计算最大矩形面积:
- 对于每个元素
h[i],计算以h[i]为最小值时的矩形面积area = h[i] * (right[i] - left[i] - 1)。 - 更新
max_area,最终返回最大矩形面积。
- 对于每个元素
这个算法的时间复杂度是 𝑂(𝑛),空间复杂度是 𝑂(𝑛),能够高效地解决这个问题。