问题描述
小S最近在分析一个数组 h1,h2,...,hN,数组的每个元素代表某种高度。小S对这些高度感兴趣的是,当我们选取任意 k 个相邻元素时,如何计算它们所能形成的最大矩形面积。
对于 k 个相邻的元素,我们定义其矩形的最大面积为:
R(k)=k×min(h[i],h[i+1],...,h[i+k−1])
即,R(k) 的值为这 k 个相邻元素中的最小值乘以 k。现在,小S希望你能帮他找出对于任意 k,R(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
解题思路
解法一:暴力法(枚举法)
-
遍历所有可能的子数组长度 k (从 1 到 n)。
-
对于每个 k,从数组起点开始遍历每个子数组,计算其最小值 min(h[i:i+k]) 并乘以 k。
-
记录每个子数组长度 k 的最大矩形面积,最后返回所有值中的最大值。
Java代码实现
public static int solution(int n, int[] array) {
int maxArea = 0;
// 枚举所有可能的子数组长度 k
for (int k = 1; k <= n; k++) {
for (int i = 0; i <= n - k; i++) {
// 找到长度为 k 的子数组中的最小值
int minHeight = Integer.MAX_VALUE;
for (int j = i; j < i + k; j++) {
minHeight = Math.min(minHeight, array[j]);
}
// 更新最大面积
maxArea = Math.max(maxArea, minHeight * k);
}
}
return maxArea;
}
时间复杂度
-
时间复杂度:O() (枚举所有子数组,计算最小值需要O(k))。
-
空间复杂度:O(1)。
解法二:单调栈法
此问题可以转化为直方图最大矩形问题,核心思路是:
- 利用单调栈快速找到每个柱形的左右边界。
- 每个柱形高度 h[i] 作为最小值时,可以形成的最大矩形宽度为: 宽度=右边界−左边界−1
- 矩形面积为: h[i]×宽度h[i]
- 遍历所有柱形,返回最大矩形面积。
Java代码实现
public static int solution(int n, int[] array) {
// Edit your code here
int res = 0, max = 0, len = n;
Stack<Integer> st = new Stack<>();
int[] newArray = new int[len + 2];
newArray[0] = 0;
newArray[newArray.length - 1] = 0;
for (int i = 0; i < array.length; i++) {
newArray[i + 1] = array[i];
}
st.push(0);
for (int right = 0; right < newArray.length; right++) {
while (!st.isEmpty()) {
int mid = st.peek();
if (newArray[right] < newArray[mid]) {
st.pop();
int left = st.peek();
int h = newArray[mid];
int w = right - left - 1;
max = Math.max(max, w * h);
} else {
break;
}
}
st.push(right);
}
return max;
}
时间复杂度
-
时间复杂度:O(n)(每个柱形入栈出栈一次)。
-
空间复杂度:O(n)(存储左右边界和栈)。
学习心得
单调栈思想
它是特殊栈结构,栈内元素需保持单调递增或递减性。按顺序遍历数据序列,栈空时新元素直接入栈;栈不空时,若新元素符合栈的单调性要求则入栈,若不符合,就不断弹出栈顶元素并做相应处理,直至栈空或新元素满足单调性要求后再入栈。
单调栈适合解决以下几类问题:
- 寻找下一个更大(小)元素:比如在整数数组中找各元素右边首个更大(小)元素,或计算柱状图最大矩形面积时确定各柱子对应的相关情况。
- 区间最值查询:特定条件下可快速确定满足单调性要求的子区间最值。
- 匹配括号相关:判断括号是否匹配以及确定匹配括号对位置等。
- 维护有序序列及快速查询:动态维护有序序列,便于快速查询元素位置及相邻元素等信息。
知识点延伸
-
单调栈技巧:
单调栈常用于快速计算左右边界问题,例如:- 直方图最大矩形面积。
- 滑动窗口最大值。
- 股票问题。
-
时间复杂度优化思路:
从暴力法到单调栈的优化,核心在于避免重复计算(如多次求最小值)。 -
延伸问题:
- 给定一个二维矩阵,求矩形区域的最大面积(最大子矩形问题)。
- 滑动窗口内最小值或最大值问题。
通过不同解法的实现,我们可以对算法效率和数据结构应用有更深入的理解。