Java 中直方图的最大矩形面积

2025年3月17日 | 阅读11分钟

在本节中,我们将探讨如何在直方图中计算最大矩形面积。

直方图中的最大矩形面积是什么?

要创建的最大矩形应由连续的条形组成。为了简单起见,我们将假定每个条形的宽度为 1。

例如,对于具有 7 个条形高度为 {7, 3, 6, 5, 6, 2, 7} 的直方图,可能的最大矩形面积为 15。最大面积以黄色突出显示。

Maximum Rectangular Area in a Histogram in Java

让我们讨论解决此问题的各种方法。

朴素方法

在此方法中,我们将逐一考虑每个条形作为起点,并从该起点开始,每次通过逐一考虑下一个条形来计算矩形面积。每次计算矩形面积时,我们将其与当前最大面积进行比较(最初,最大面积初始化为 0)。

文件名:LargestRectArea.java

输出

The maximum rectangular area is: 15

时间复杂度:在上面的程序中,我们使用了 2 次幂的嵌套 for 循环。因此,该程序的总复杂度为 O(n2),其中 n 是输入数组中存在的元素总数。

分治法

该概念是找到输入数组中值为最小的索引。一旦找到值为最小的索引,最大面积就是以下三个值中的最大值。

  1. 最小值的左侧的最大面积(不包括最小值)
  2. 最小值的右侧的最大面积(不包括最小值)。
  3. 条形总数乘以最小条形值。

观察下面的程序。

输出

The maximum rectangular area is: 15

时间复杂度:在上面的程序中,时间复杂度取决于两件事:一是线段树,二是查找最大矩形面积。构建线段树所需的时间复杂度为 O(n),查找最大矩形面积所需的时间复杂度为 O(log(n))。因此,时间复杂度变为 O(n) + O(n * log(n)),渐进时间复杂度变为 O(n * log(n)),其中 n 是输入数组中存在的元素总数。

如果我们比较以上两个程序,会发现后一个程序更优化,因为它解决问题所需的时间更少。但是,我们可以进一步优化它。让我们在以下方法中进行查看。

方法:使用栈

让我们看看使用栈查找矩形面积的算法。

步骤 1:创建一个栈用于压入和弹出元素。

步骤 2:从第一个条形开始,对每个条形 "histArr[j]" 执行以下任务,其中 'j' 从 0 到 s - 1。

  1. 如果栈为空或 histArr[ij] 比栈顶的条形长,则将 'j' 压入栈。
  2. 如果当前条形比栈顶的条形短,则不断从栈顶弹出条形,直到栈顶的条形较大。假设移除的条形是 histArr[top]。以 histArr[top] 作为最小条形计算矩形面积。对于 histArr[top],'左索引'是栈中前一个(在 top 前面)的条形,而 '右索引'是 'j'(当前索引)。

步骤 3:如果栈中还有一些条形,则逐一弹出栈中的所有条形,并对每个移除的条形重复步骤 2(ii)。

文件名:LargestRectArea2.java

输出

The maximum rectangular area is: 15

使用辅助数组

另一种方法是找到直方图中每个条形的前一个更小条形和后一个更小条形,这将通过两个辅助数组来实现。请参阅以下算法。

步骤 1:首先,我们采用两个辅助数组 leftSmaller[] 和 rightSmaller[],并将它们分别初始化为负数和 n。

步骤 2:对于每个元素,我们在 rightSmaller[] 和 leftSmaller[] 数组中分别保留后一个更小元素和前一个更小元素的索引。这需要 O(n) 的时间。

步骤 3:对于每个条形,我们通过将第 j 个条形作为 leftSmaller[j] 和 rightSmaller[j] 范围内的最短条形来计算面积,并将其乘以 leftSmaller[j] 和 rightSmaller[j] 的差值。

步骤 4:可以通过比较每个条形的面积来计算最大面积。不同条形的面积在步骤 3 中计算。

文件名:LargestRectArea3.java

输出

The maximum rectangular area is: 15

时间复杂度:最后两种方法的复杂度为 O(n),其中 n 是数组中存在的元素总数。