题目描述
给定一个包含 N 个元素的数组 array,每个元素代表高度,数组中的元素分别为 h1, h2, ..., hn。对于 k 个相邻的元素,我们定义它的最大面积如下:
R(k) = k * min(h[i], h[i+1], ..., h[i+k-1])
需要找到 R(k) 的最大值,其中 k 是任意的合法长度。也就是说,我们希望找到一段连续子数组,使得这段子数组的最小高度乘以它的宽度最大。
例子
- 输入:数组
[1, 2, 3, 4, 5] - 输出:
9,因为面积最大的矩形是[3, 4, 5],面积为3 * 3 = 9。
问题分析
这个问题可以归类为 最大矩形面积 的问题。需要找到一个连续子数组,使其面积最大。该面积由子数组的长度乘以子数组中的最小高度得到。
解决思路
我们可以使用 动态规划 来解决这个问题。动态规划的思想在于通过记录之前的计算结果,来推导后续的结果,从而避免重复计算。
- 用
dp[i]表示以位置i结尾的最大面积。 - 遍历数组,对每个位置
i,我们尝试找到以该位置结尾的连续子数组的最大面积。 - 对于每一个新的位置
i,向左遍历,记录当前的最小高度minHeight,然后计算面积并更新最大值。
通过以上思路,我们能够在一次遍历的过程中,找到以每个位置为结尾的最大矩形面积,并在过程中不断更新全局的最大面积。
动态规划实现过程
- 初始化
dp数组用于存储以每个位置结尾的最大面积。 - 使用双重循环,外层循环遍历每个元素作为结尾,内层循环向左遍历找到最小高度。
- 通过
Math.min()更新最小高度,计算当前面积,并通过Math.max()更新最大面积。
以下是 Java 代码的实现:
public class Main {
public static int solution(int n, int[] array) {
if (n == 0 || array == null || array.length == 0) {
return 0;
}
int[] dp = new int[n];
int maxArea = 0;
for (int i = 0; i < n; i++) {
int minHeight = array[i];
dp[i] = array[i];
maxArea = Math.max(maxArea, dp[i]);
for (int j = i - 1; j >= 0; j--) {
minHeight = Math.min(minHeight, array[j]);
dp[j] = minHeight * (i - j + 1);
maxArea = Math.max(maxArea, dp[j]);
}
}
return maxArea;
}
public static void main(String[] args) {
System.out.println(solution(5, new int[] { 1, 2, 3, 4, 5 }) == 9);
System.out.println(solution(6, new int[] { 6, 2, 5, 4, 5, 1, 6 }) == 12);
System.out.println(solution(4, new int[] { 1, 1, 1, 1 }) == 4);
System.out.println(solution(0, new int[] {}) == 0);
System.out.println(solution(3, new int[] { 2, 4, 2 }) == 6);
}
}
代码解析
-
边界检查:如果数组为空或者长度为
0,直接返回0。 -
动态规划数组
**dp**:用于存储以每个位置结尾的最大面积。 -
双重循环:
- 外层循环遍历每个元素
i。 - 内层循环从位置
i向左遍历,通过不断更新minHeight来计算面积。
- 外层循环遍历每个元素
-
最大面积更新:使用
maxArea变量来持续记录遇到的最大面积。
时间复杂度分析
该算法的时间复杂度为 O(n^2) ,因为对于每个元素 i,我们可能需要遍历之前的所有元素来更新最小高度。这使得在最坏情况下,需要进行 n * (n - 1) / 2 次比较。
尽管时间复杂度相对较高,但这种实现方法简单明了,便于理解。在数据规模不大的情况下可以有效使用。
总结
通过这道题目,我们学习了如何通过动态规划来解决最大矩形面积问题。核心思想是找到每个位置结尾的最大面积,并在过程中不断更新全局最大值。动态规划的方法虽然可能在时间复杂度上不够最优,但其简洁性和可理解性使其非常适合用于理解问题的求解过程。