【LeetCode】84. 柱状图中最大的矩形

84. 柱状图中最大的矩形

知识点:单调栈

题目描述

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

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

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

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

解法一:暴力法

以每个元素为中心向左右扩散,这个元素就是这个高度。

暴力法
class Resolution:
    def get_biggest(self, heights):
        max_area = 0
        for i, height in enumerate(heights):
            p, q = i+1, i-1
            while p < len(heights) and heights[p] >= height:
                p += 1
            while q >= 0 and heights[q] >= height:
                q -= 1
            area = height * (p-q-1)
            max_area = max(max_area, area)
        return max_area
r = Resolution()

解法二:单调栈

上面的解法需要去寻找每个元素它左右两边第一个比它小的元素下标,这时候就可以确定宽度进而确定面积了。第一个比它大或者小的,这不就是可以用单调栈吗?
可以维持一个单调递增栈,if遇到更大的元素,那以它为高的矩形还不能确定,当遇到小的时候,对于栈顶元素而言,栈的下一个元素比其小,要入栈的比其小,所以矩形就确定了。
想一下栈里应该存什么,求面积无非就是宽乘以高,if存高度,那宽度就没有办法确定,但是if是存下标,那宽度和高度都可以确定。
对于单调栈的问题,重点是要弄清楚当元素出栈的时候,意味着什么。比如寻找一个数组里第一个比它大的元素,那就可以维持一个单调递减栈。当遇到大的元素时,出栈。这时候出栈就意味着找到了第一个比自己大的元素;对于这个题,出栈就意味着确定了以它为高的矩阵。

  • 未优化
class Resolution:
    def get_biggest(self, heights):
        max_area = 0
        stack = []
        for i, height in enumerate(heights):
            while stack and height < heights[stack[-1]]:
                cur_height = heights[stack.pop()]
                while stack and cur_height == heights[stack[-1]]: #可能存在相同的值;
                    stack.pop()
                if stack:   #栈为空和非空不一样
                    width = i - stack[-1] - 1
                else:
                    width = i
                area = cur_height * width
                max_area = max(max_area, area)
            stack.append(i)
        while stack:  # 仍然在栈里的元素;
            cur_height = heights[stack.pop()]
            while stack and cur_height == heights[stack[-1]]:
                stack.pop()
            if stack:
                width = len(heights) - stack[-1] - 1
            else:
                width = len(heights)
            max_area = max(max_area, cur_height * width)
        return max_area
  • 优化
    在首尾各加一个高度为0,这时候就不用单独判断了,因为任何值都会比0大,所以都会入栈,又因为任何值都比0大,所以都会出栈;
class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        size = len(heights)
        res = 0
        heights = [0] + heights + [0]
        # 先放入哨兵结点,在循环中就不用做非空判断
        stack = [0]
        size += 2

        for i in range(1, size):
            while heights[i] < heights[stack[-1]]:
                cur_height = heights[stack.pop()]
                cur_width = i - stack[-1] - 1
                res = max(res, cur_height * cur_width)
            stack.append(i)
        return res

相关链接

题解

posted @ 2022-04-04 21:11  Curryxin  阅读(73)  评论(0编辑  收藏  举报
Live2D