中等题:最大矩形面积问题
问题描述
小S最近在分析一个数组h1,h2,...,hn,数组的每个元素代表某种高度。小S对这些高度感兴趣的是,当我们选取任意 k 个相邻元素时,如何计算它们所能形成的最大矩形面积。
对于 k 个相邻的元素,我们定义其矩形的最大面积为:
即, 的值为这 个相邻元素中的最小值乘以 。现在,小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, array = [4, 4, 4, 4]
输出: 16
解题思路
暴力解法:
首先题目很好理解,就是在k个连续的元素里面找到那个最小的元素乘上一个k。然后我们要在诸多这样的值里面找一个最大的。这样就很自然的想到去使用暴力枚举去破解,对于每一位的数字,都遍历一遍他后面的数字,遇到一个情况就更新一次max最后找到最大值。
那么时间复杂度为:
并未使用额外数据结构,空间复杂度为
def solution(n, array):
max_area = 0
for i in range(n):
min_value = array[i]
for j in range(i, n):
min_value = min(min_value, array[j])
current_area = (j - i + 1) * min_value
max_area = max(max_area, current_area)
return max_area
我们可以考虑使用单调栈的方法来快速确定连续区域的最小值
单调栈解法:
首先来思考一下具体的测试样例,比如[1,2,3,4,5] 在元素1的这个位置时,我们发现1是里面最小的 所以考虑让他最大化 肯定是 1 * 5。
如果在元素2的位置,他的最大宽度就是4 最大化的值就是 2 * 4
依次类推
3 * 3
4 * 2
5 * 1
我们可以发现 他这个宽度的左边界取决于左边有没有比他小的 并且是离这个元素最近的那个位置。
那么又考虑到 我们想要 k个连续数里 最小的那个数乘上一个k
所以宽度的右边界与左边界的寻找相同 即找到他右边比他小的第一个位置。
为了简化计算 我们添加两个虚拟边界 0
那么以h[i]为高度的最大矩形面积就是
def solution(n, heights):
stack = []
max_area = 0
heights = [0] + heights + [0]
for i in range(len(heights)):
# 当当前柱子高度小于栈顶柱子高度时,计算栈顶柱子的面积
while stack and heights[i] < heights[stack[-1]]:
height = heights[stack.pop()] # 栈顶柱子的高度
width = i - stack[-1] - 1 # 当前柱子与新栈顶之间的宽度
max_area = max(max_area, height * width)
stack.append(i)
return max_area
每个数值最多入栈和出栈一次,时间复杂度为
工具的运用
在做这道题的时候,其实我是想都没想直接使用暴力解法的。但是这样的时间复杂度太高了。这里给掘金的刷题提个建议,像leetcode一样告诉我们测试样例的取值范围,时间复杂度太高的不给通过,才能push大家挖掘更好的解法。
那么在我想到这样不行之后,我就询问豆包AI有没有更好的办法。豆包AI会给我提出使用单调栈的建议。那么有了方向后重新思考问题 就可以得出更好的解法了。