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

69 阅读5分钟

题目解析:二分数字组合

小S正在分析一个数组 h_1, h_2, ..., h_N,数组的每个元素代表某种高度。小S感兴趣的是,当我们选取任意 k 个相邻元素时,如何计算它们所能形成的最大矩形面积。

对于 k 个相邻的元素,我们定义其矩形的最大面积为:

R(k) = k * min(h[i], h[i + 1], ..., h[i + k - 1])

即,R(k) 的值为这 k 个相邻元素中的最小值乘以 k。现在,小S希望你能帮他找出对于任意 kR(k) 的最大值。

测试样例

样例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

问题理解

给定一个数组 array,我们需要找到任意 k 个相邻元素所能形成的最大矩形面积。具体来说,对于任意 k 个相邻元素,矩形的最大面积为这 k 个元素中的最小值乘以 k。我们需要找到所有可能的 k 中,最大的矩形面积。

数据结构与算法选择

  1. 暴力解法

    • 遍历所有可能的 k(从 1 到 n)。
    • 对于每个 k,遍历数组中所有可能的 k 个相邻元素,计算其矩形面积。
    • 时间复杂度为 O(n^3),效率较低。
  2. 优化解法

    • 使用单调栈(Monotonic Stack)来优化查找最小值的过程。
    • 单调栈可以帮助我们在 O(n) 时间内找到每个元素作为最小值时,能形成的最大矩形面积。

算法步骤

  1. 初始化

    • 使用一个栈来存储数组元素的索引。
    • 初始化 max_area 为 0,用于记录最大矩形面积。
  2. 遍历数组

    • 对于每个元素 array[i],如果当前元素大于或等于栈顶元素对应的值,则将其索引压入栈中。
    • 如果当前元素小于栈顶元素对应的值,则弹出栈顶元素,并计算以该元素为最小值的矩形面积。
    • 计算面积时,宽度为当前索引 i 减去栈顶元素的索引(如果栈为空则为 i)。
  3. 处理剩余元素

    • 遍历结束后,栈中可能还有元素,依次弹出并计算以这些元素为最小值的矩形面积。
  4. 返回结果

    • 返回 max_area

代码框架

def solution(n, array):
    stack = []
    max_area = 0
    index = 0

    while index < n:
        # If this bar is higher than the bar at stack top, push it to the stack
        if not stack or array[index] >= array[stack[-1]]:
            stack.append(index)
            index += 1
        else:
            # Pop the top
            top_of_stack = stack.pop()
            # Calculate the area with array[top_of_stack] as the smallest (or minimum height) bar
            area = (array[top_of_stack] *
                    ((index - stack[-1] - 1) if stack else index))
            # Update max area, if needed
            max_area = max(max_area, area)

    # Now pop the remaining bars from stack and calculate area
    while stack:
        top_of_stack = stack.pop()
        area = (array[top_of_stack] *
                ((index - stack[-1] - 1) if stack else index))
        max_area = max(max_area, area)

    return max_area

关键步骤解释

  1. 栈的使用

    • 栈中存储的是数组元素的索引,这样可以方便地计算矩形的宽度。
    • 当遇到一个比栈顶元素小的元素时,弹出栈顶元素并计算面积。
  2. 面积计算

    • 面积的计算公式为 array[top_of_stack] * width,其中 width 是当前索引 index 减去栈顶元素的索引(如果栈为空则为 index)。
  3. 处理剩余元素

    • 遍历结束后,栈中可能还有元素,这些元素对应的矩形面积也需要计算。

通过上述步骤,我们可以在 O(n) 时间内找到最大矩形面积。

心得

当前代码展示了如何使用单调栈(Monotonic Stack)来解决最大矩形面积的问题。通过分析和学习这段代码,你可以学到以下几个重要的编程和算法概念:

1. 单调栈(Monotonic Stack)

单调栈是一种特殊的栈结构,栈中的元素保持单调递增或单调递减的顺序。在这段代码中,单调栈用于在 O(n) 时间内找到每个元素作为最小值时,能形成的最大矩形面积。

  • 栈的基本操作

    • stack.append(index):将元素索引压入栈中。
    • stack.pop():弹出栈顶元素。
    • stack[-1]:访问栈顶元素。
  • 单调栈的应用

    • 通过维护一个单调递增的栈,可以在常数时间内找到每个元素的下一个更小元素。
    • 在弹出栈顶元素时,计算以该元素为最小值的矩形面积。

2. 时间复杂度优化

通过使用单调栈,代码将时间复杂度从 O(n^3) 优化到 O(n),极大地提高了算法的效率。

  • 遍历数组
    • 每个元素最多入栈和出栈一次,因此总的时间复杂度为 O(n)

3. 边界条件处理

代码在处理边界条件时表现良好,例如当栈为空时,计算面积的宽度为当前索引 index

  • 边界检查
    • 在计算面积时,使用 (index - stack[-1] - 1) if stack else index 来处理栈为空的情况。

4. 代码结构与可读性

代码结构清晰,逻辑流程明确,注释详细,有助于理解和维护代码。

  • 变量命名

    • 变量命名如 stackmax_areaindex 等都很直观,有助于理解代码的逻辑。
  • 注释

    • 代码中添加了详细的注释,解释了每一步的操作,这对于理解和维护代码非常有帮助。

5. 测试用例

代码中包含了一个测试用例,用于验证代码的正确性。通过添加更多的测试用例,可以进一步验证代码的鲁棒性。

  • 测试用例设计
    • 通过不同的输入数据,验证代码在各种情况下的表现。

6. 代码复用性

可以将计算面积的部分提取为一个单独的函数,以提高代码的复用性和可读性。

  • 函数提取
    • 将计算面积的逻辑提取为 calculate_area 函数,使代码更加模块化。

总结

通过学习这段代码,我可以掌握单调栈的应用、时间复杂度优化、边界条件处理、代码结构与可读性、测试用例设计以及代码复用性等重要的编程和算法概念。这些知识不仅有助于解决类似的最大矩形面积问题,还能提升我的整体编程能力。