题目解析
这道题的核心是寻找数组中任意 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) 的最大值。解题的关键是如何高效计算和比较这些矩形面积。
问题分解
-
问题核心
- 对于数组中的每个元素 h[i]h[i],需要向左和向右扩展,找到其“支配范围”:
- 向左扩展直到遇到比 h[i]h[i] 更小的元素,确定左边界。
- 向右扩展直到遇到比 h[i]h[i] 更小的元素,确定右边界。
- 元素 h[i]h[i] 的“支配范围”决定了它在矩形中可以作为最小值的最大跨度(宽度)。
- 对于数组中的每个元素 h[i]h[i],需要向左和向右扩展,找到其“支配范围”:
-
单调栈优化
- 使用单调递增栈来高效确定每个柱子的左右边界:
- 左边界:从左到右扫描数组时,栈中存储所有尚未确定右边界的元素索引。
- 右边界:从右到左扫描数组,同样通过单调栈计算。
- 每次从栈中弹出一个元素时,可以直接确定该柱子的“支配范围”,并计算相应矩形的面积。
- 使用单调递增栈来高效确定每个柱子的左右边界:
-
矩形面积计算
-
对于每个柱子 h[i]h[i],矩形面积计算公式为:
Area=h[i]×(RightBoundary[i]−LeftBoundary[i]−1)Area=h[i]×(RightBoundary[i]−LeftBoundary[i]−1)
-
最终返回所有面积中的最大值。
-
算法步骤
-
初始化
- 定义一个栈存储数组索引。
- 定义变量
maxArea用于记录最大面积。
-
遍历数组
- 从左到右扫描,维护一个单调递增栈。
- 每当发现当前柱子高度小于栈顶柱子的高度时:
- 弹出栈顶元素,计算以该元素为最小高度的矩形面积。
- 更新最大面积。
-
清理栈中剩余柱子
- 扫描结束后,栈中可能仍有未处理的柱子。
- 按照同样的方式计算剩余柱子的矩形面积。
-
返回结果
- 返回
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);
}
} `
算法复杂度分析
-
时间复杂度:
- 每个柱子最多被栈操作两次(一次入栈、一次出栈),因此总体复杂度为 O(n)O(n)。
-
空间复杂度:
- 主要用于存储栈和边界数组,空间复杂度为 O(n)O(n)。
总结
本题通过单调栈优化,将暴力枚举的 O(n2) 解法降低到 O(n),大幅提高了效率。该方法不仅适用于求解直方图中最大矩形面积问题,还可以扩展到其他类似区间问题中,具有很高的应用价值。