代码随想录算法训练营第60天 | 一刷结束篇 84.柱状图中最大的矩形

代码随想录系列文章目录

一刷总结篇



84.柱状图中最大的矩形

题目链接
这道题和接雨水是两个相似的题,相辅相成的那种,双指针是过不了力扣的会超时,所以我也不写了

dp 普通思路

先说一下思路,计算公式是什么捏?遍历每一块矩形,它对应的最大面积就是heights[i] * (左边第一个小于它高度的坐标 - 右边第一个小于它高度的坐标 - 1)
然后动态更新一下这个res就行了

难就难在本题要记录每个柱子 左边第一个小于该柱子的下标,而不是左边第一个小于该柱子的高度。

所以需要循环查找,也就是下面在寻找的过程中使用了while,详细请看下面注释

def largestRectangleArea(self, heights: List[int]) -> int:
        n = len(heights)
        dpl, dpr = [0] * n, [0] * n
        res = 0

        # 记录每个柱子的左侧第一个矮一级的柱子的下标
        dpl[0] = -1
        for i in range(1, n):
            temp = i-1
            #当左边持续较高,尝试再左边的,直到找到第一个矮一点的柱子
            while temp >= 0 and heights[temp] >= heights[i]:
                temp = dpl[temp]
            #跳出这个循环说明有可能找到了
            dpl[i] = temp #把下标赋给当前的dp[i]
        
        dpr[n-1] = n
        for i in range(n-2, -1, -1):
            temp = i + 1
            while temp <= n-1 and heights[temp] >= heights[i]:
                temp = dpr[temp]
            dpr[i] = temp

        for i in range(n):
            area = heights[i] * (dpr[i] - dpl[i] -1)
            res = max(res, area)
        return res

单调栈

这道题和接雨水是呼应的,接雨水找的是两边第一个大于它高度的柱子,这道题是找两边第一个小于它高度的下标

这就导致在这题中单调栈的顺序是从大到小的

在这里插入图片描述
此时大家应该可以发现其实就是栈顶栈顶的下一个元素以及要入栈的三个元素组成了我们要求最大面积的高度和宽度

思路
单调栈的思路还是,当前遍历到的位置i,如果height[i] > height[stack[-1]], 我们直接入栈

如果说 height[i] == height[stack[-1]], 我们pop出那个,入栈新的,因为我们要的是坐标嘛

然后,遇到小于栈顶的情况的话,height[i] < height[stack[-1]], 我们开始更新我们的结果

怎么计算呢?还是老三样,栈顶作为mid坐标,是拿来用height[mid]作高度的,然后pop出来。此时的新栈顶作为leftidx, i 是rightidx,这俩是用来做宽度的

与接雨水不同的是,这道题的首尾两个柱子都可以作为核心柱子,做最大面积的尝试

所以为此所做的操作是,输入数组首尾各补上一个0
但是遍历的时候,还是栈先入0, 然后i从1到 len(new_heights), 这样才能确保边缘两根做主心骨的情况

def largestRectangleArea(self, heights: List[int]) -> int:
        stack = [0]
        res = 0
        heights = [0] + heights + [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 stack and heights[i] < heights[stack[-1]]:
                    mid = stack[-1]
                    stack.pop()
                    if stack:
                        h = heights[mid]
                        w = i - stack[-1] - 1
                        res = max(res, h*w)
                stack.append(i)
        return res

一刷总结篇

刚到日本的时候,我也是想着秋招要试试水,所以刷题也没停下。
当时九月初我是想着复习一下dp,于是就是照着代码随想录的dp篇章开始做。大概做了几天后,看见朋友圈卡哥发的代码随想录算法训练营,大家一起抱团取暖。于是我毫不犹豫的报名参加了。

两个月以来,不管多忙,不管有多懒,每天我都按时的把今天该做的任务完成了。实事求是的说,刷代码随想录还是一件很愉快的事情。把一个复杂的题,用逻辑疏通每一个关节,明白其中的难点和用到的数据结构,是一件很有成就感的小事。

希望接下来,我能更有勇气去面对前方的困难(我一直没上岸哈哈),希望我能坚定自己选择的路,人生能选择去做自己的喜欢的事,活的比任何人都要自由。
就像YOASAOBI-群青中描述的那样,能够做自己喜欢的事情,所获得的不止是乐趣而已。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值