题目解析最大矩形面积问题 | 豆包MarsCode AI刷题

85 阅读4分钟

题目要求

给定一个高度数组 array,每个元素表示柱子的高度。我们需要在数组中找到任意相邻 k 个柱子所能形成的最大矩形面积。矩形面积的计算公式是:R(k) = k * min(h[i], h[i+1], ..., h[i+k-1]),即选择 k 个相邻柱子,取最小高度乘以 k 得到面积。目标是找到所有可能的 R(k) 中的最大值。 这是一个经典的最大矩形面积问题。

思路

给定一个高度数组 array,我们需要找到一个矩形的最大面积,矩形的宽度为 k(代表相邻元素的数量),并且高度为这 k 个元素中的最小值。

  1. 暴力枚举宽度 k:我们可以尝试所有可能的宽度 k(从 1n),对于每个宽度 k,我们从数组的起始位置到 n - k + 1 的位置,找出长度为 k 的子数组中最小的高度,然后计算面积。
  2. 计算面积:对于每个 k 和每个起始位置 i 的子数组,面积为 k * min(array[i], ..., array[i + k - 1])。然后我们在所有计算得到的面积中取最大值。
  3. 优化思路:尽管暴力解法简单,但时间复杂度较高,为 O(n^2)。可以通过单调栈的方式优化。单调栈可以帮助我们在 O(n) 的时间内找到每个元素左右两边第一个小于它的元素的位置,从而有效地确定每个高度作为最小值时的最大宽度范围。

对于每个位置 i,当我们以 array[i] 作为高度时,我们需要找到它左右两边第一个比它低的柱子。这是因为:

  • 只有在 array[i] 高度内,才能形成一个矩形。
  • 通过找到左右边界,我们确定了可以扩展的范围,也就是矩形的宽度。

例子解释

假设 array = [2, 1, 5, 6, 2, 3],我们一步一步地计算每个柱子的最大面积。

第一步:找出 leftright 数组

  • 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],我们根据 leftright 数组计算最大面积。

以位置 i=2(高度为 5)为例

  • left[2] = 1right[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),适合处理长输入的数组。