问题描述
给定一个高度数组 array,我们需要找到该数组中所有连续子数组的最大矩形面积。对于每个子数组,矩形的高度由该子数组中的最小高度决定,面积由子数组的长度和最小高度决定。要求我们优化这个计算过程,避免暴力枚举每个子数组。
思路分析
-
暴力解法:
- 在暴力解法中,我们会枚举每个子数组,并计算其最小高度及面积。时间复杂度大约是 O(n2)O(n^2)O(n2),对于较大的数组效率较低。
-
栈优化:
- 为了提高效率,我们可以使用单调栈来解决这个问题。栈在这里的作用是,保持一个递增的柱子高度顺序。当遇到一个比栈顶元素矮的柱子时,我们就可以计算栈顶柱子能形成的最大矩形面积。
-
单调栈的原理:
-
遍历每一个柱子(即数组的每个元素),维护一个递增的栈。当遇到一个比栈顶柱子矮的柱子时:
- 弹出栈顶元素,计算该栈顶元素能够形成的最大矩形面积(宽度是当前柱子的位置减去栈顶元素的下一个位置)。
- 继续重复直到栈顶元素小于或等于当前元素。
-
最后处理栈中剩余的元素。
-
-
复杂度分析:
- 时间复杂度:每个元素最多会入栈一次和出栈一次,因此时间复杂度是 O(n)O(n)O(n)。
- 空间复杂度:栈的大小最多为 O(n)O(n)O(n),因此空间复杂度是 O(n)O(n)O(n)。
代码实现
import java.util.Stack;
public class Main {
// 计算最大矩形面积
public static int solution(int n, int[] array) {
// 用来存储栈的索引
Stack<Integer> stack = new Stack<>();
int maxArea = 0;
for (int i = 0; i < n; i++) {
// 当栈不为空,并且当前值小于栈顶值时,计算栈顶元素的最大矩形面积
while (!stack.isEmpty() && array[stack.peek()] > array[i]) {
int h = array[stack.pop()]; // 取出栈顶元素
int width = (stack.isEmpty()) ? i : i - stack.peek() - 1; // 宽度为当前索引与栈顶索引的差
maxArea = Math.max(maxArea, h * width); // 更新最大面积
}
// 当前元素入栈
stack.push(i);
}
// 处理剩下的栈中的元素
while (!stack.isEmpty()) {
int h = array[stack.pop()];
int width = (stack.isEmpty()) ? n : n - stack.peek() - 1; // 宽度为剩余部分的长度
maxArea = Math.max(maxArea, h * width); // 更新最大面积
}
return maxArea;
}
public static void main(String[] args) {
// 测试用例
System.out.println(solution(5, new int[]{1, 2, 3, 4, 5}) == 9); // 输出: 9
System.out.println(solution(6, new int[]{5, 4, 3, 2, 1, 6}) == 9); // 输出: 9
System.out.println(solution(4, new int[]{4, 4, 4, 4}) == 16); // 输出: 16
}
}
代码分析
-
solution(int n, int[] array)方法:- 使用一个栈来维护柱子的索引,栈中的柱子始终是递增的。
- 对于每个柱子,如果当前柱子比栈顶柱子小,就开始弹出栈顶柱子并计算以栈顶柱子为最小高度的矩形面积。矩形的宽度是当前柱子和栈顶柱子之间的差值。
- 处理完当前柱子后,将当前柱子的索引压入栈中。
- 在所有柱子遍历完之后,栈中可能还有一些柱子,计算这些柱子能够形成的最大矩形面积。
-
main(String[] args)方法:- 该方法包含了多个测试用例,通过调用
solution方法并打印结果来验证代码的正确性。
- 该方法包含了多个测试用例,通过调用
时间复杂度分析
- 时间复杂度:每个柱子入栈一次,出栈一次,因此总体的时间复杂度为 O(n)O(n)O(n),其中 nnn 是数组的长度。
- 空间复杂度:栈的最大大小为 O(n)O(n)O(n),因此空间复杂度为 O(n)O(n)O(n)。
测试用例
-
输入:
[1, 2, 3, 4, 5]- 输出:
9 - 解释: 最大的矩形面积是
[3, 4, 5],最小高度为 3,宽度为 3,因此面积为 3 * 3 = 9。
- 输出:
-
输入:
[5, 4, 3, 2, 1, 6]- 输出:
9 - 解释: 最大的矩形面积是
[5, 4, 3],最小高度为 3,宽度为 3,因此面积为 3 * 3 = 9。
- 输出:
-
输入:
[4, 4, 4, 4]- 输出:
16 - 解释: 所有元素都相等,最大矩形面积为
4 * 4 = 16。
- 输出:
总结
- 该算法通过单调栈的方法优化了暴力计算最大矩形面积的问题,将时间复杂度从 O(n2)O(n^2)O(n2) 降低到 O(n)O(n)O(n)。
- 栈的使用能够有效地减少重复计算,提升效率。
- 代码实现清晰简洁,通过多个测试用例验证了算法的正确性。