最大矩形面积问题

121 阅读4分钟

题目解析

这道题的核心是寻找数组中任意 kk 个相邻元素组成的矩形区域的最大面积。每个矩形的面积由 kk 个相邻元素中最小的高度乘以 kk 计算得出,即:

R(k)=k×min⁡(h[i],h[i+1],...,h[i+k−1])R(k)=k×min(h[i],h[i+1],...,h[i+k−1])

我们需要找出整个数组中所有可能的 R(k)R(k) 的最大值。解题的关键是如何高效计算和比较这些矩形面积。


问题分解

  1. 问题核心

    • 对于数组中的每个元素 h[i]h[i],需要向左和向右扩展,找到其“支配范围”:
      • 向左扩展直到遇到比 h[i]h[i] 更小的元素,确定左边界。
      • 向右扩展直到遇到比 h[i]h[i] 更小的元素,确定右边界。
    • 元素 h[i]h[i] 的“支配范围”决定了它在矩形中可以作为最小值的最大跨度(宽度)。
  2. 单调栈优化

    • 使用单调递增栈来高效确定每个柱子的左右边界:
      • 左边界:从左到右扫描数组时,栈中存储所有尚未确定右边界的元素索引。
      • 右边界:从右到左扫描数组,同样通过单调栈计算。
    • 每次从栈中弹出一个元素时,可以直接确定该柱子的“支配范围”,并计算相应矩形的面积。
  3. 矩形面积计算

    • 对于每个柱子 h[i]h[i],矩形面积计算公式为:

      Area=h[i]×(RightBoundary[i]−LeftBoundary[i]−1)Area=h[i]×(RightBoundary[i]−LeftBoundary[i]−1)

    • 最终返回所有面积中的最大值。


算法步骤

  1. 初始化

    • 定义一个栈存储数组索引。
    • 定义变量 maxArea 用于记录最大面积。
  2. 遍历数组

    • 从左到右扫描,维护一个单调递增栈。
    • 每当发现当前柱子高度小于栈顶柱子的高度时:
      • 弹出栈顶元素,计算以该元素为最小高度的矩形面积。
      • 更新最大面积。
  3. 清理栈中剩余柱子

    • 扫描结束后,栈中可能仍有未处理的柱子。
    • 按照同样的方式计算剩余柱子的矩形面积。
  4. 返回结果

    • 返回 maxArea,即数组中所有矩形面积的最大值。

测试样例分析

样例 1

  • 输入n = 5, array = [1, 2, 3, 4, 5]
  • 分析:
    • 数组元素单调递增,面积最大矩形是由 3 个元素 [3,4,5][3,4,5] 组成的矩形,面积为 3×3=93×3=9。
  • 输出9

样例 2

  • 输入n = 6, array = [5, 4, 3, 2, 1, 6]
  • 分析:
    • 数组元素先递减后递增,最大矩形面积仍然为 3×3=93×3=9(由 [3,3,3][3,3,3] 组成)。
  • 输出9

样例 3

  • 输入n = 4, array = [4, 4, 4, 4]
  • 分析:
    • 所有元素高度相等,最大面积由整个数组组成的矩形 4×4=164×4=16。
  • 输出16

`import java.util.Stack; public class Main { public static int solution(int n, int[] array) { // 创建一个栈来存放柱子的索引 Stack stack = new Stack<>(); int maxArea = 0;

     // 遍历所有的柱子
     for (int i = 0; i < n; i++) {
         // 如果当前柱子的高度小于栈顶柱子的高度,则需要计算面积
         while (!stack.isEmpty() && array[i] < array[stack.peek()]) {
             int height = array[stack.pop()];  // 当前弹出的柱子的高度
             int width = stack.isEmpty() ? i : i - stack.peek() - 1;  // 宽度计算
             maxArea = Math.max(maxArea, height * width);
         }
         stack.push(i);  // 将当前柱子索引压入栈
     }

     // 清理栈中剩余的柱子
     while (!stack.isEmpty()) {
         int height = array[stack.pop()];
         int width = stack.isEmpty() ? n : n - stack.peek() - 1;
         maxArea = Math.max(maxArea, height * width);
     }

     return maxArea;
}

public static void main(String[] args) {
    // Add your test cases here
    
    System.out.println(solution(5, new int[]{1, 2, 3, 4, 5}) == 9);
}

} `

算法复杂度分析

  1. 时间复杂度:

    • 每个柱子最多被栈操作两次(一次入栈、一次出栈),因此总体复杂度为 O(n)O(n)。
  2. 空间复杂度:

    • 主要用于存储栈和边界数组,空间复杂度为 O(n)O(n)。

总结

本题通过单调栈优化,将暴力枚举的 O(n2) 解法降低到 O(n),大幅提高了效率。该方法不仅适用于求解直方图中最大矩形面积问题,还可以扩展到其他类似区间问题中,具有很高的应用价值。