代码随想录27期|Python|Day54|​单调栈|​42. 接雨水|84. 柱状图中最大的矩形

news2024/12/29 10:38:06

42. 接雨水

根据常识可以归纳出,对于每一列所能够存住的水的高度

Height = min(LeftMax, RightMax) - height

也就是,当前列的存水高度 = 左侧和右侧柱子的最大高度的较小值,减去当前列的柱子高度,所得到的差值。

可以验证第4列:Height = min(2, 3) - 1 = 1,其中2是最左边的最高的柱子(3列)高度,3是右边最高的柱子的高度(7列),1是当前4列的柱子的高度。

解法一:双指针

双指针解法主要的思想是牺牲空间换时间,也就是在最后遍历全部的柱子高度求解雨水高度之前,先把每一列所对应的最左边和最右边的最高的柱子算出来。因此需要两个for循环,循环前都需要进行初始化。

        leftmax[0] = height[0]
        for i in range(1, len(height)):
            leftmax[i] = max(height[i], leftmax[i-1])

        rightmax[len(height) - 1] = height[len(height) - 1]
        for i in range(len(height) - 2, -1, -1):
            rightmax[i] = max(height[i], rightmax[i+1])

至此,已经得到了每一列的左右最高的柱子,下面只需要遍历最后一次柱子,按照公式进行求解就可以了。 

class Solution(object):
    def trap(self, height):
        """
        :type height: List[int]
        :rtype: int
        """

        # 双指针解法
        res  = 0
        leftmax = [0] * len(height)
        rightmax = [0] * len(height)

        leftmax[0] = height[0]
        for i in range(1, len(height)):
            leftmax[i] = max(height[i], leftmax[i-1])

        rightmax[len(height) - 1] = height[len(height) - 1]
        for i in range(len(height) - 2, -1, -1):
            rightmax[i] = max(height[i], rightmax[i+1])

        for i in range(len(height)):
            Height = min(leftmax[i], rightmax[i]) - height[i]
            if Height > 0:
                res += Height
        return res

解法二:单调栈

单调栈的性质是能够维护一个有顺序的高度索引的序列。

为什么是按照行来计算呢?

因为我们在一次操作中只能得到当前列(中间列)和左右两边列的高度,而不能得到左边最高值和右边最高值。

举个例子,对于列5(高度0),我们一次只能获取到列4(高度1)和列6(高度1),根据计算智能得到水位高度为1,但是因为看不到左右最高值,所以列5的上方是否还有水(列5的实际水位高度是2)就没有方法获取到。

单调栈解法的原理

维护一个从栈底部到顶部为单调减高度的索引栈(栈的开口向右,可以想象成一个向右下的斜坡),那么在遍历到一个比栈顶元素大的元素的时候,恰好组成了一个V字,也就是中间低,两边高。这三个数字(栈顶、栈顶-1(左边的高度索引),遍历到的height(右边高度索引))就组成了一个储水的结构。

此时,只需要计算出左右索引之间的距离,在计算出左右索引对应的高度的最小值,即可得到储水的体积。

然后,栈顶的元素相当于被使用了,所以需要弹出,再判断当前遍历到的高度和新的栈顶元素的高度的大小(也就是之前的左侧的索引),最后,直到遍历到的元素比栈顶元素小(或者相等),再加入到栈中,组成一个递减的序列。

class Solution(object):
    def trap(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        # 单调栈解法
        res = 0
        stack = []
        for i in range(len(height)):
            while stack and height[i] > height[stack[-1]]:
                mid_height = stack.pop()  # 弹出来的是中间柱子的高度索引(作为最低的底部的高度)
                if stack:  # 确保当前的stack还有值,也就是左边界存在
                    h = min(height[stack[-1]], height[i]) - height[mid_height]
                    w = i - stack[-1] - 1
                    res += h * w
            stack.append(i)
        return res

84. 柱状图中最大的矩形

什么时候能够取到最大的矩形面积?

以一个柱子作为矩形高度的基准,向左向右遍历到的第一个比他小的柱子,作为矩形的左右边界,此时计算出的矩形面积是该柱子为最大高度基准时最大的。

2,2,34,5,4,33

蓝色边界的面积:3 * 5 = 15;

红色边界的面积:7 * 2 = 14;

所以可以确定,对于局部值而言,最大的面积在两侧第一个小于中心高度的区间之间。

解法一:双指针

对于本题,因为需要宽度,所以需要在双指针遍历的时候储存左右第一个小于当前高度值的索引。

        leftminidx[0] = -1
        for i in range(1, len(heights)):
            t = i - 1  # i左边的索引
            while t >= 0 and heights[i] <= heights[t]:
                t = leftminidx[t]
            leftminidx[i] = t

以左侧为例,因为需要向左侧拓展,如果一直比当前的柱子高度高,那么就将其索引值设置为自身,直到循环打破,储存第一个小于当前高度的索引。

这样做的好处是,在最后一次求解面积的遍历时,只需要进行面积的计算和结果的更新即可。

class Solution(object):
    def largestRectangleArea(self, heights):
        """
        :type heights: List[int]
        :rtype: int
        """

        # 双指针解法
        res = 0

        leftminidx = [0] * len(heights)
        rightminidx = [0] * len(heights)

        leftminidx[0] = -1
        for i in range(1, len(heights)):
            t = i - 1  # i左边的索引
            while t >= 0 and heights[i] <= heights[t]:
                t = leftminidx[t]
            leftminidx[i] = t
        
        rightminidx[len(heights)-1] = len(heights)
        for i in range(len(heights)-2, -1, -1):
            t = i + 1
            while t <= len(heights) - 1 and heights[i] <= heights[t]:
                t = rightminidx[t]
            rightminidx[i] = t 

        for i in range(len(heights)):
            area = heights[i] * (rightminidx[i] - leftminidx[i] - 1)
            res = max(res, area)
        return res

解法二:单调栈

本题的分析上和接雨水相反,因为接雨水的栈结构实际上是构成了一个谷形来接住雨水,所以找的是第一个大于当前元素的值。但是本题实际上是构成一个山峰,所以需要找到的是第一个小于当前值的索引。

因此,单调栈的顺序是从栈底到栈顶递增。

每次遍历到的值(右边界)、栈顶元素(中间值)、栈顶元素的后一个值(左边界索引)构成了局部最大矩形。

class Solution(object):
    def largestRectangleArea(self, heights):
        """
        :type heights: List[int]
        :rtype: int
        """
        # 单调栈解法
        res = 0
        stack = []
        heights.insert(0,0)  # 加上0防止溢出
        heights.append(0)  # 加上0防止溢出
        
        for i in range(len(heights)):
            while stack and heights[i] < heights[stack[-1]]:
                mid_height = stack.pop()
                if stack:
                    Height = heights[mid_height]  # 中心值作为高度
                    Width = i - stack[-1] - 1  # 不算上两个边界索引
                    # print(stack)
                    res = max(res, Height * Width)
            stack.append(i)

        return res

Day54完结!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2131964.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

spring常用注解(10)@Order

一、 1、作用 加Order()注解&#xff0c;在注解中加入数字&#xff0c;数字越小&#xff0c;优先级越高&#xff0c;最先执行。 2、使用方法 &#xff08;1&#xff09;自定义顺序 Component Order(1) public class XxxFilter extends OncePerRequestFilter{}Component Or…

什么品牌的宠物空气净化器性价比最高?352/希喂/霍尼韦尔/有哈/IAM实测对比

我开着一家猫咪咖啡馆&#xff0c;我们店貌美小猫可没少给我带来回头客~先给大家看看我的招财猫们 开了三年了&#xff0c;也是前不久店里才开始有点盈利&#xff0c;开始那段时间没少收到投诉&#xff0c;差点就干不下去了。店里养着的猫多&#xff0c;平时鱼油、冻干也没稍微…

foc入门

FOC(Field Oriented Control)磁场定向控制 foc,磁场定向控制&#xff0c;通过控制无刷电机三相电流&#xff0c;来实现对无刷电机的角度扭矩的控制。 首先先要理解无刷电机的原理&#xff0c;我们以三槽两极内转子电机进行讲解&#xff0c; 相较于有刷电机&#xff0c;无刷电…

乱弹篇(47)渔友絮语

中秋节连着国庆节长假很快就要来临&#xff0c;这对于久未远行旅游的人来说&#xff0c;真是拉满的幸福日子&#xff0c;因此本“人民体验官”特意推广人民日报官方微博文化产品《收藏&#xff01;中秋假期博物馆看展攻略》。 截图&#xff1a;来源“人民体验官”推广平台 人民…

Linux编译内核选项说明

内核功能选择 编译内核时出现的提示信息是在描述内核配置界面中的导航和操作方式。具体解释如下&#xff1a; Arrow keys navigate the menu: 使用箭头键可以在菜单中上下左右移动。 <Enter> selects submenus ---> (or empty submenus ----): 按下回车键可以选择一个…

【白话树】之 树的基本知识、存储结构和二叉树转换

快速导航 一、树的基础概念1. 树的定义&#xff1a;2. 树的特点:3. 树的常用术语&#xff1a;4. 树的简单分类&#xff1a; 二、树的存储结构1.顺序存储1) 双亲表示法2) 孩子表示法3) 双亲孩子表示法 2.链式存储1) 孩子链表表示法2) 孩子兄弟表示法 三、树、森林和二叉树的转换…

根据NVeloDocx Word模板引擎生成Word(五)

前面几篇基本上介绍完了NVeloDocx的基础用法&#xff0c;绝大部分的需求其实都是这些基础的东西&#xff0c;本篇将介绍2个不常用但是实际的业务场景&#xff1a; 1、图片列表输出&#xff1b; 比如在E6开发平台生成的客户端中&#xff0c;图片列表往往是这样显示的&#xff…

【数据结构】第八节:链式二叉树

个人主页&#xff1a; NiKo 数据结构专栏&#xff1a; 数据结构与算法 源码获取&#xff1a;Gitee——数据结构 一、二叉树的链式结构 typedef int BTDataType; typedef struct BinaryTreeNode {BTDataType data;struct BinaryTreeNode* left; // 左子树根节点struct BinaryT…

2024年沈阳都市圈电竞大赛 暨TGA腾讯电竞运动会辽宁省选拔赛盛大开赛

去年&#xff0c;由沈阳市体育局主办的“2023年沈阳都市圈首届电竞大赛暨TGA浑南之夏辽宁省英雄联盟选拔赛”成功举办。通过搭建赛事平台&#xff0c;营造了沈阳都市圈电竞氛围&#xff0c;促进了电子竞技全业态发展。 今年&#xff0c;“2024年沈阳都市圈电竞大赛暨TGA腾讯电…

Day24_0.1基础学习MATLAB学习小技巧总结(24)——图形对象属性值的设置和查询

利用空闲时间把碎片化的MATLAB知识重新系统的学习一遍&#xff0c;为了在这个过程中加深印象&#xff0c;也为了能够有所足迹&#xff0c;我会把自己的学习总结发在专栏中&#xff0c;以便学习交流。 参考书目&#xff1a;《MATLAB基础教程 (第三版) (薛山)》 之前的章节都是…

vue3项目实现全局国际化

本文主要梳理vue3项目实现全项目格式化&#xff0c;例如在我前面文章使用若依创建vue3的项目中&#xff0c;地址&#xff1a;若依搭建vue3项目在导航栏中切换&#xff0c;页面中所有的组件的默认语言随之切换&#xff0c;使用的组件库依旧是element-plus&#xff0c;搭配vue-i1…

LeetCode --- 414周赛

题目列表 3280. 将日期转换为二进制表示 3281. 范围内整数的最大得分 3282. 到达数组末尾的最大得分 3283. 吃掉所有兵需要的最多移动次数 一、将日期转换成二进制表示 题目本质就是将数字转成二进制字符串&#xff0c;可以类比将十进制数字的每一位拆开拼成字符串&#x…

【Redis】redis5种数据类型(list)

目录 基本介绍 命令 LPUSH LPUSHX RPUSH RPUSHX LRANGE LPOP RPOP LINDEX LINSERT LLEN LREM LTRIM LSET 阻塞版本的命令 BLPOP 内部编码 基本介绍 list相当于c的双端队列deque 区分获取和删除的区别 lindex能获取到元素的值lrem也能返回被删除元素的值 命…

一条SQL实现GPT大模型【完全看不懂】

用一条SQL实现GPT大模型&#xff0c;简直让人不可思议&#xff0c;但是俄罗斯一位名叫Quassnoi的SQL牛人做到了&#xff0c;Quassnoi每年只写一条SQL&#xff0c;但是每条SQL都非常复杂&#xff1a; 2021年&#xff0c;用SQL绘制新冠病毒的3D图片 2022年&#xff0c;用SQL模拟…

为何初创数字影像企业纷纷选择入驻孵化基地?

在当今数字化时代&#xff0c;数字影像行业正蓬勃发展&#xff0c;越来越多的初创数字影像企业如雨后春笋般涌现。而这些充满活力与创新的初创企业&#xff0c;为何纷纷选择入驻数字影像企业孵化基地呢&#xff1f; 首先&#xff0c;数字影像企业孵化基地为初创数字影像企业提供…

再次进阶 舞台王者 第八季完美童模全球赛形象大使【邱玳莹】赛场秀场超燃合集!

7月20-23日&#xff0c;2024第八季完美童模全球总决赛在青岛圆满落幕。在盛大的颁奖典礼上&#xff0c;一位才能出众的少女——邱玳莹&#xff0c;迎来了她舞台生涯的璀璨时刻。 形象大使——邱玳莹&#xff0c;以璀璨童星之姿&#xff0c;优雅地踏上完美童模盛宴的绚丽舞台&am…

基于图像级监督和自训练的跨模态肿瘤分割转换器模型|文献速递--Transformer架构在医学影像分析中的应用

Title 题目 Image-level supervision and self-training for transformer-basedcross-modality tumor segmentation 基于图像级监督和自训练的跨模态肿瘤分割转换器模型。 01 文献速递介绍 深度学习在各种医学图像分析应用中展现了出色的性能和潜力&#xff08;Chen等&…

C语言 12 函数

其实函数在一开始就在使用了&#xff1a; // 这就是定义函数 int main() { ... }程序的入口点就是main函数&#xff0c;只需要将程序代码编写到主函数中就可以运行了&#xff0c;不过这个函数只是由我们来定义&#xff0c;而不是我们来调用。 当然&#xff0c;除了主函数之…

SMT | Kriging代理模型原理及应用

前言 代理模型工具箱 (surrogate modeling toolbox, SMT) 是一个基于Python开发的第三方包&#xff0c;其中包含代理模型方法、采样技术和基准测试函数。有关SMT的详细介绍参见&#xff1a; SMT | 代理模型Python工具包推荐 SMT可实现几个与高斯过程回归相关的代理模型&#x…

串口输出时:英文正常输出、中文乱码输出

一、问题&#xff1a;英文正常输出&#xff0c;英文乱码输出 二、解决方法 1、查看自己使用的串口助手的编码格式 2、查看自己使用输出的文件编码格式 以记事本的格式查看&#xff0c;原则上这两种应该保持相同&#xff0c;如果不相同&#xff0c;就需要把这个文件去另保存一…