今天给大家分享一下每日刷题的题目解析和经验分享,本系列预计会推出五期,今天给大家带来的是第二期的分享。
最大矩形面积问题
问题描述
小S最近在分析一个数组数组的每个元素代表某种高度。小S对这些高度感兴趣的是,当我们选取任意 个相邻元素时,如何计算它们所能形成的最大矩形面积。
对于 个相邻的元素,我们定义其矩形的最大面积为:
即, 的值为这 个相邻元素中的最小值乘以 。现在,小S希望你能帮他找出对于任意 的最大值。
测试样例
样例 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
解题方法1——暴力求解
public static int solution(int n, int[] array) {
int maxArea = 0;
// 遍历所有可能的 k 值
for (int k = 1; k <= n; k++) {
// 遍历数组,计算以每个元素为起点的 k 个相邻元素的最小值
for (int i = 0; i <= n - k; i++) {
int minHeight = array[i];
// 计算 k 个相邻元素的最小值
for (int j = 1; j < k; j++) {
if (array[i + j] < minHeight) {
minHeight = array[i + j];
}
}
// 计算面积并更新最大面积
int area = k * minHeight;
if (area > maxArea) {
maxArea = area;
}
}
}
return maxArea;
}
解题思路
-
遍历所有可能的
k值:- 外层循环从
k = 1到k = n,遍历所有可能的k值。k表示选取的相邻元素的个数。
- 外层循环从
-
遍历数组,计算以每个元素为起点的
k个相邻元素的最小值:- 对于每个
k值,内层循环从i = 0到i = n - k,遍历数组,计算以每个元素为起点的k个相邻元素的最小值。
- 对于每个
-
计算
k个相邻元素的最小值:- 对于每个起点
i,使用一个内层循环从j = 1到j = k - 1,计算k个相邻元素的最小值。
- 对于每个起点
-
计算面积并更新最大面积:
- 计算面积
area = k * minHeight,其中minHeight是k个相邻元素的最小值。 - 如果计算的面积
area大于当前的最大面积maxArea,则更新maxArea。
- 计算面积
-
返回最大面积:
- 最终返回
maxArea,即所有可能的k值中最大的矩形面积。
- 最终返回
复杂度分析
时间复杂度
暴力求解代码使用了三重循环来计算最大矩形面积:
- 外层循环遍历所有可能的 (k) 值,从 1 到 (n)。
- 中层循环遍历数组,计算以每个元素为起点的 (k) 个相邻元素的最小值。
- 内层循环计算 (k) 个相邻元素的最小值。
- 外层循环执行 (n) 次。
- 中层循环执行 (n - k + 1) 次。
- 内层循环执行 (k - 1) 次。
因此,总的时间复杂度为 (O(n^3))。
空间复杂度
当前代码的空间复杂度主要由以下部分组成:
- 输入数组
array,占用 (O(n)) 的空间。 - 其他变量(如
maxArea,minHeight,area等),占用常数空间 (O(1))。
因此,总的空间复杂度为 (O(n))。
算法优化
-
单调栈:单调栈是一种常用的数据结构,用于在 (O(n)) 时间内解决与区间最小值相关的问题。我们可以使用单调栈来维护一个递增的栈,栈中存储的是数组元素的索引。
-
计算最大矩形面积:通过单调栈,我们可以快速计算出以每个元素为最小值的最大矩形面积。具体步骤如下:
- 遍历数组,对于每个元素,如果栈顶元素的高度小于当前元素的高度,则将当前元素的索引入栈。
- 如果栈顶元素的高度大于等于当前元素的高度,则弹出栈顶元素,并计算以栈顶元素为最小值的最大矩形面积。
- 计算面积时,宽度为当前元素的索引与栈顶元素的索引之差。
-
边界处理:在遍历结束后,栈中可能还有元素,我们需要继续处理这些元素,直到栈为空。
public static int solution(int n, int[] array) {
int maxArea = 0;
Stack<Integer> stack = new Stack<>();
// 遍历数组
for (int i = 0; i <= n; i++) {
int h = (i == n) ? 0 : array[i];
// 如果栈不为空且当前高度小于栈顶元素对应的高度
while (!stack.isEmpty() && h < array[stack.peek()]) {
int height = array[stack.pop()];
int width = stack.isEmpty() ? i : i - stack.peek() - 1;
// 计算面积并更新最大面积
int area = height * width;
if (area > maxArea) {
maxArea = area;
}
}
// 将当前索引入栈
stack.push(i);
}
return maxArea;
}
复杂度分析
时间复杂度
当前代码使用了单调栈来计算最大矩形面积,具体步骤如下:
- 遍历数组:外层循环遍历数组中的每个元素,时间复杂度为 (O(n))。
- 单调栈操作:在每次遍历中,单调栈的操作(入栈和出栈)最多执行 (O(n)) 次。
- 外层循环执行 (n + 1) 次(包括最后一个虚拟元素)。
- 单调栈操作(入栈和出栈)最多执行 (2n) 次(每个元素最多入栈和出栈一次)。
因此,总的时间复杂度为 (O(n))。
空间复杂度
当前代码的空间复杂度主要由以下部分组成:
- 输入数组
array,占用 (O(n)) 的空间。 - 单调栈
stack,最多存储 (n) 个元素,占用 (O(n)) 的空间。 - 其他变量(如
maxArea,h,height,width,area等) ,占用常数空间 (O(1))。
因此,总的空间复杂度为 (O(n))。