问题描述
小S最近在分析一个数组 ,数组的每个元素代表某种高度。小S对这些高度感兴趣的是,当我们选取任意 个相邻元素时,如何计算它们所能形成的最大矩形面积。对于 个相邻的元素,我们定义其矩形的最大面积为:即, 的值为这 个相邻元素中的最小值乘以 。现在,小S希望你能帮他找出对于任意 , 的最大值。
测试样例
样例1:
输入:
n = 5 ,array = [1, 2, 3, 4, 5]输出:9
样例2:
输入:
n = 6 ,array = [5, 4, 3, 2, 1, 6]输出:9
样例3:
输入:
n = 4 ,a = [4, 4, 4, 4]输出:16
思路分析:
我们有一个数组 array,数组中的每个元素表示一个直方图的柱子的高度。我们要找出所有可能的连续柱子组合(至少一个柱子)中,能够覆盖的最大矩形面积。
关键点在于理解并确定每个柱子作为矩形的“高度”时,可以向左右两边分别延伸多少距离,使得以这个柱子为高所构成的矩形面积最大。
计算左右边界:
- 左侧边界:对于每个柱子
i,我们需要找到左边第一个比它低的柱子left[i]。如果不存在,则默认为-1。这样,以i为中心向左扩展的宽度就是i - left[i]。 - 右侧边界:同样,我们需要找到右边第一个比它低的柱子
right[i]。如果不存在,则默认为数组末尾N。这样,以i为中心向右扩展的宽度是right[i] - i。
矩阵面积计算:
对于每个柱子 i:
- 它向左的最大扩展宽度为
i - left[i], - 向右的最大扩展宽度为
right[i] - i, - 所以以这个柱子为高的矩形面积为:
height[i] * (right[i] - left[i] - 1)。
最终答案是所有柱子可能的矩形面积中的最大值。
代码实现:
from typing import List
def find_boundaries(heights: List[int]) -> tuple:
stack = []
n = len(heights)
left = [-1] * n
right = [n] * n
for i in range(n):
while stack and heights[stack[-1]] >= heights[i]:
right[stack.pop()] = i
if stack:
left[i] = stack[-1]
stack.append(i)
return left, right
def solution(n: int, array: List[int]) -> int:
left, right = find_boundaries(array)
max_area = 0
for i in range(n):
width = right[i] - left[i] - 1
area = array[i] * width
max_area = max(max_area, area)
return max_area
if __name__ == "__main__":
assert solution(5, [1, 2, 3, 4, 5]) == 9
print("测试通过!")
代码中的 find_boundaries 函数解析
这个函数用于计算每个柱子的左右边界。
-
初始化两个数组
left和right,分别记录每个柱子的左边界和右边界,默认情况下,左边界为-1,右边界为数组的最后一个下标加一。 -
利用两个单调递增的栈来分别计算
left和right。- 当前柱子
i要入栈时,需要弹出所有高于等于它的柱子,直到遇到第一个小于它的柱子或栈空; - 栈顶元素就是当前柱子左边第一个比它低的柱子(若存在),或栈空则无;
- 右边相同的道理,只不过方向相反。
- 当前柱子
总结
- 使用两个辅助栈来快速找到每个柱子的左右边界,减少了不必要的比较次数。
- 通过动态规划的方式,每次更新最大面积,直至找到全局最优解。
- 最后返回所有可能的矩形面积中的最大值作为解。