题目要求
给定一个高度数组 array,每个元素表示柱子的高度。我们需要在数组中找到任意相邻 k 个柱子所能形成的最大矩形面积。矩形面积的计算公式是:R(k) = k * min(h[i], h[i+1], ..., h[i+k-1]),即选择 k 个相邻柱子,取最小高度乘以 k 得到面积。目标是找到所有可能的 R(k) 中的最大值。
这是一个经典的最大矩形面积问题。
思路
给定一个高度数组 array,我们需要找到一个矩形的最大面积,矩形的宽度为 k(代表相邻元素的数量),并且高度为这 k 个元素中的最小值。
- 暴力枚举宽度
k:我们可以尝试所有可能的宽度k(从1到n),对于每个宽度k,我们从数组的起始位置到n - k + 1的位置,找出长度为k的子数组中最小的高度,然后计算面积。 - 计算面积:对于每个
k和每个起始位置i的子数组,面积为k * min(array[i], ..., array[i + k - 1])。然后我们在所有计算得到的面积中取最大值。 - 优化思路:尽管暴力解法简单,但时间复杂度较高,为
O(n^2)。可以通过单调栈的方式优化。单调栈可以帮助我们在O(n)的时间内找到每个元素左右两边第一个小于它的元素的位置,从而有效地确定每个高度作为最小值时的最大宽度范围。
对于每个位置 i,当我们以 array[i] 作为高度时,我们需要找到它左右两边第一个比它低的柱子。这是因为:
- 只有在
array[i]高度内,才能形成一个矩形。 - 通过找到左右边界,我们确定了可以扩展的范围,也就是矩形的宽度。
例子解释
假设 array = [2, 1, 5, 6, 2, 3],我们一步一步地计算每个柱子的最大面积。
第一步:找出 left 和 right 数组
left[i]:对于每个柱子array[i],找到其左边第一个比它小的柱子的位置。right[i]:对于每个柱子array[i],找到其右边第一个比它小的柱子的位置。
对于 array = [2, 1, 5, 6, 2, 3],可以得到以下结果:
left = [-1, -1, 1, 2, 1, 4]right = [1, 6, 4, 4, 6, 6]
解释:
left[2] = 1表示在位置2的柱子高度为5,它左边第一个小于5的柱子在位置1。right[2] = 4表示在位置2的柱子高度为5,它右边第一个小于5的柱子在位置4。
第二步:计算每个柱子的最大矩形面积
对于每个柱子 array[i],我们根据 left 和 right 数组计算最大面积。
以位置 i=2(高度为 5)为例:
left[2] = 1,right[2] = 4- 这个柱子左右可以扩展的宽度为
right[i] - left[i] - 1 = 4 - 1 - 1 = 2 - 以高度
5、宽度2计算面积:5 * 2 = 10
因此,对于位置 i=2,我们得到了一个可能的矩形面积 10。
其他位置计算: 类似地,计算其他位置的最大面积,然后取所有面积中的最大值。
最终结果为 10。
代码实现
def solution(n, array):
max_area = 0
stack = []*n # 单调栈,左边、右边第一个比它小的元素的位置
res = [-1]*n
for i in range(n):
while stack and array[stack[-1]] >= array[i]:
topi = stack.pop()
left_i = stack[-1] if stack else -1
res[topi] = (left_i,i)
stack.append(i)
while stack:
idx = stack.pop()
lidx = stack[-1] if stack else -1
res[idx] = (lidx, n)
print(res)
for i in range(n):
width = res[i][1] - res[i][0] -1
max_area = max(max_area, array[i]*width)
return max_area
- left 数组:保存了每个位置左边第一个比它小的元素的索引。
- right 数组:保存了每个位置右边第一个比它小的元素的索引。
- 最后,对于每个位置
i,我们可以计算以array[i]为高度的最大矩形面积array[i] * (right[i] - left[i] - 1)。 - 该算法的时间复杂度为
O(n),适合处理长输入的数组。