柱状图中最大的矩阵 单调栈

84. 柱状图中最大的矩形

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

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

示例 1:

输入:heights = [2,1,5,6,2,3]

输出:10

解释:最大的矩形为图中红色区域,面积为 10

示例 2

输入: heights = [2,4]

输出: 4

思路:

  这道题是个困难题。但实际上就是利用单调栈来解决

  我们要明确一个结论:对于每一个柱子,都可以以它的高度为矩形高度,然后向两边扩展形成一个矩形——所以我们只需要对每一个柱子都计算出它能向两边扩展形成的最大矩形,取最大的即可

  从一个柱子,如何向两边扩展呢?很显然,如果它两边的柱子比它高,说明它不会被两边的高度限制,可以自由扩展;如果一旦遇到了比它低的柱子,就无法扩展了,那么就扩展到这个柱子之前即可。

  发现没有,这就是找“下一个较小”问题——直接条件反射:单调栈

  单调栈的模板和详细介绍可以直接参考:

每日温度 单调栈_TranSad的博客-CSDN博客

  所以接下来,我们直接可以通过单调栈模板得到:每一个柱子与下一个较小值的距离。

  但根据我们的模板,我们得到的“下一个”是指右边的下一个,即只能得到右边的柱子当中比当前柱子小的距离——那如何得到左边的下一个较小值距离呢?方法很简单:我们单调栈模板几乎可以不用动,只需要把给定数组倒置传入模板,再将最终得到的结果倒置,就可以得到“前一个较小值的距离”了。

  最终我们知道了每一个柱子到两边的下一个较小值距离,相当于得到了矩形的宽,就可以直接宽乘以高得到这个柱子所能形成的最大矩形了。

代码:

class Solution(object):

def largestRectangleArea(self, heights):

    #闭着眼写单调栈模板

        stack=[]

        lenth = len(heights)

        right_res=[0]*lenth

        for i in range(lenth-1,-1,-1):

            while(stack and heights[stack[-1]]>=heights[i]):#下一个较小用>=

                stack.pop()

            right_res[i]=stack[-1]-i if stack else lenth-i #离它的距离带上-i

            stack.append(i)

        #至此下一个较小值距离已经求完了,放在了right_res里


        #接下来求“前一个较小值距离”

        #思路就是对height翻转过来,然后对得到的res再翻转

        #模板都不用任何改变就首尾两次翻转 即可

        heights1=heights[::-1]#翻转

        left_res = [0]*lenth

        stack=[]

        for i in range(lenth-1,-1,-1):

            while(stack and heights1[stack[-1]]>=heights1[i]):

                stack.pop()

            left_res[i]=stack[-1]-i if stack else lenth-i #离它的距离 

            stack.append(i)

        left_res=left_res[::-1]#翻转结果 拿到向左的下一个较小值

        #正式计算啦

        maxx=0

        for i,h in enumerate(heights):

            #每个柱子可以形成的最大矩形,就是向两边扩展的长度加起来乘以高度

            area = (right_res[i]+left_res[i]-1)*h

            maxx=max(maxx,area)

        return maxx

小结:

  这道题的思路是很明确的,但一定要有单调栈的基础!这样我们就可以把问题层次化拨开,很清楚地知道我们每一步都在做什么,先做什么在做什么。代码里看似很复杂,但无非就是使用了两次一模一样的单调栈模板,就是两次的输入取了个反。

  虽然我这样的实现复杂度可能并不算低,但这样写可以最大程度地保证好用和好实现——对于简单题来说,重点可能是复杂度上面的优化,但对于这么一道困难题来说,能实现和通过才是首先要关心的问题。我个人还是很在乎实用性和好实现的,即使会牺牲一些复杂度,毕竟我得先保全自身能做出来再说别的~

posted @   JunanP  阅读(5)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示