Leetcode刷题笔记60:单调栈3(84. 柱状图中最大的矩形)

191 阅读1分钟

导语

leetcode刷题笔记记录,主要记录题目包括:

Leetcode 84. 柱状图中最大的矩形

题目描述

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

 

示例 1:

输入: heights = [2,1,5,6,2,3]
输出: 10
解释: 最大的矩形为图中红色区域,面积为 10

示例 2:

输入: heights = [2,4]
输出: 4

 

提示:

  • 1 <= heights.length <=105
  • 0 <= heights[i] <= 104

解法

与接雨水类似,这道题目求得是内部的面积,所以首先考虑一下暴力解法的思路:

  • 遍历每个柱子,找到每个柱子左边第一个比自己矮的柱子和右边第一个比自己矮的柱子
  • 计算宽高,算面积,取最大值

这里,求左边第一个小的值和右边第一个小的值就可以使用单调栈,但是这里的单调栈是单调递减的(从栈顶到栈底的方向),同时,需要考虑两种特殊情况:

  1. 假设柱子都是单调递减的,即nums=[8,6,4,2],那么将不会有柱子进入到宽高计算环节
  2. 同理,假如是递增的,由于第一个元素进栈后,第二个元素比第一个元素大,那么计算宽高环节仅有两个变量,无法表示left。

所以,这里需要对首尾各加入一个0,缓解上面的问题。

image.png

完整版代码如下:

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        stack = [0]  # 初始化一个栈,用于存放柱子的索引,栈内的柱子高度是单调递增的
        result = 0  # 初始化最大矩形面积为 0

        # 在原始高度数组的两端各添加一个高度为 0 的柱子,以便清空栈
        heights = [0] + heights + [0]
        
        # 从第二个柱子开始遍历(因为我们添加了一个高度为 0 的柱子在开头)
        for i in range(1, len(heights)):
            # 如果当前柱子高于栈顶柱子
            if heights[i] > heights[stack[-1]]:
                stack.append(i)  # 直接将当前柱子加入栈中

            # 如果当前柱子和栈顶柱子一样高
            elif heights[i] == heights[stack[-1]]:
                stack.pop()  # 移除栈顶柱子
                stack.append(i)  # 将当前柱子加入栈中

            # 如果当前柱子比栈顶柱子矮
            else:
                # 依次移除栈中高于当前柱子的柱子,并计算可能的矩形面积
                while len(stack) > 0 and heights[i] < heights[stack[-1]]:
                    mid = stack[-1]  # 获取栈顶柱子的索引
                    stack.pop()  # 移除栈顶柱子
                    if len(stack) > 0:
                        left = stack[-1]  # 获取新的栈顶柱子作为左边界
                        right = i  # 当前柱子作为右边界
                        h = heights[mid]  # 矩形的高
                        w = right - left - 1  # 矩形的宽
                        # 更新最大矩形面积
                        result = max(result, h * w)
                
                stack.append(i)  # 将当前柱子加入栈中

        return result  # 返回最大矩形面积