返回

柱状图中面积最大的矩形:突破性策略带来最优解

见解分享

问题的定义

给定一个由 n 个非负整数构成的数组 heights,其中每个整数代表柱状图中一个柱子的高度。柱子彼此相邻,且宽度均为 1。我们的目标是找到一个矩形,该矩形由柱状图中的柱子勾勒而成,且该矩形的面积为所有可能矩形中最大的。

动态规划算法

为了解决该问题,我们可以使用动态规划算法。动态规划是一种将问题分解成较小的子问题,然后逐步求解这些子问题,最终得到整个问题的解的一种算法技术。

在我们的问题中,我们可以将每个柱子看作是一个子问题。对于每个柱子,我们可以计算出以该柱子为右边界的所有可能矩形的最大面积。然后,我们将这些最大面积值取最大值,即可得到整个柱状图中面积最大的矩形。

单调栈的运用

为了计算出以某个柱子为右边界的所有可能矩形的最大面积,我们可以使用单调栈这一数据结构。单调栈是一种栈数据结构,其特点是栈中的元素始终保持单调递减或单调递增。

在我们的问题中,我们可以将柱状图中的每个柱子看作一个元素,并将其压入单调栈中。当我们遇到一个柱子比栈顶元素更高的柱子时,我们将其压入栈中。当我们遇到一个柱子比栈顶元素矮的柱子时,我们将栈顶元素弹出,并计算以该弹出元素为右边界的所有可能矩形的最大面积。

算法步骤

下面是该算法的具体步骤:

  1. 初始化单调栈为空。
  2. 从左到右遍历柱状图中的每个柱子。
  3. 如果当前柱子比栈顶元素更高,则将其压入栈中。
  4. 如果当前柱子比栈顶元素矮,则重复以下操作:
    • 将栈顶元素弹出,并计算以该弹出元素为右边界的所有可能矩形的最大面积。
    • 将当前柱子压入栈中。
  5. 重复步骤 2 和步骤 3,直到遍历完所有的柱子。
  6. 将栈中剩余的所有元素弹出,并计算以这些元素为右边界的所有可能矩形的最大面积。

算法示例

考虑以下柱状图:

[2, 1, 5, 6, 2, 3]

按照上述算法的步骤,我们首先将柱状图中的每个柱子压入单调栈中:

[2]
[2, 1]
[2, 1, 5]
[2, 1, 5, 6]
[2, 1, 5, 6, 2]
[2, 1, 5, 6, 2, 3]

当我们遇到第一个矮柱子时,即柱子 1,我们将其弹出,并计算以该柱子为右边界的所有可能矩形的最大面积。该矩形由柱子 2 和柱子 1 组成,面积为 2 * 2 = 4。

[2]
[2, 1, 5]
[2, 1, 5, 6]
[2, 1, 5, 6, 2]
[2, 1, 5, 6, 2, 3]

然后,我们将柱子 2 压入栈中。

[2]
[2, 2]
[2, 2, 5]
[2, 2, 5, 6]
[2, 2, 5, 6, 2]
[2, 2, 5, 6, 2, 3]

当我们遇到第二个矮柱子时,即柱子 5,我们将其弹出,并计算以该柱子为右边界的所有可能矩形的最大面积。该矩形由柱子 2、柱子 1 和柱子 5 组成,面积为 3 * 3 = 9。

[2]
[2, 2]
[2, 2, 6]
[2, 2, 6, 6]
[2, 2, 6, 6, 2]
[2, 2, 6, 6, 2, 3]

然后,我们将柱子 6 压入栈中。

[2]
[2, 2]
[2, 2, 6]
[2, 2, 6, 6]
[2, 2, 6, 6, 2, 2]
[2, 2, 6, 6, 2, 2, 3]

当我们遇到第三个矮柱子时,即柱子 2,我们将其弹出,并计算以该柱子为右边界的所有可能矩形的最大面积。该矩形由柱子 2、柱子 1、柱子 5 和柱子 6 组成,面积为 4 * 4 = 16。

[2]
[2, 2]
[2, 2, 6]
[2, 2, 6, 6]
[2, 2, 6, 6, 2, 3]
[2, 2, 6, 6, 2, 3]

然后,我们将柱子 6 压入栈中。

[2]
[2, 2]
[2, 2, 6]
[2, 2, 6, 6, 3]
[2, 2, 6, 6, 2, 3]
[2, 2, 6, 6, 2, 3]

当我们遇到最后一个矮柱子时,即柱子 3,我们将其弹出,并计算以该柱子为右边界的所有可能矩形的最大面积。该矩形由柱子 2、柱子 1、柱子 5、柱子 6 和柱子 3 组成,面积为 5 * 5 = 25。

[2]
[2, 2]
[2, 2, 6]
[2, 2, 6, 6]
[2, 2, 6, 6, 2]
[2, 2, 6, 6, 2, 3]

然后,我们将柱子 6 压入栈中。

[2]
[2, 2]
[2, 2, 6]
[2, 2, 6, 6]
[2, 2, 6, 6, 2, 2]
[2, 2, 6, 6, 2, 3]

最后,我们将栈中剩余的元素弹出,并计算以这些元素为右边界的所有可能矩形的最大面积。该矩形由柱子 2、柱子 1、柱子 5、柱子 6 和柱子 2 组成,面积为 5 * 5 = 25。

因此,整个柱状图中面积最大的矩形由柱子 2、柱子 1、柱子 5 和柱子 6 组成,面积为 25。

示例代码

def largest_rectangle_area(heights):
    """
    计算柱状图中面积最大的矩形。

    参数:
    heights: 柱状图中每个柱子的高度。

    返回:
    面积最大的矩形的面积。
    """

    # 初始化单调栈。
    stack = []

    # 初始化最大面积。
    max_area = 0

    # 从左到右遍历柱状图中的每个柱子。
    for i, height in enumerate(heights):
        # 如果当前柱子比栈顶元素更高,则将其压入栈中。
        while stack and height < heights[stack[-1]]:
            # 将栈顶元素弹出,并计算以该弹出元素为右边界的所有可能矩形的最大面积。
            top = stack.pop()
            width = i if not stack else i - stack[-1] - 1
            max_area = max(max_area, heights[top] * width)

        # 将当前柱子压入栈中。
        stack.append(i)

    # 将栈中剩余的所有元素弹出,并