【LeetCode刷题笔记(8-2)】【Python】【接雨水】【单调栈】【困难】

news2024/9/28 15:21:38

文章目录

  • 引言
  • 接雨水
    • 题目描述
    • 提示
  • 解决方案2:【单调栈】
  • 结束语

【接雨水】

【LeetCode刷题笔记(8-1)】【Python】【接雨水】【动态规划】【困难】

引言

编写通过所有测试案例的代码并不简单,通常需要深思熟虑理性分析。虽然这些代码能够通过所有的测试案例,但如果不了解代码背后的思考过程,那么这些代码可能并不容易被理解和接受。我编写刷题笔记的初衷,是希望能够与读者们分享一个完整的代码是如何在逐步的理性思考下形成的。我非常欢迎读者的批评和指正,因为我知道我的观点可能并不完全正确,您的反馈将帮助我不断进步。如果我的笔记能给您带来哪怕是一点点的启示,我也会感到非常荣幸。同时,我也希望我的分享能够激发您的灵感和思考,让我们一起在编程的道路上不断前行~

接雨水

题目描述

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

在这里插入图片描述
图片来源

提示

  • n == height.length
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105

解决方案2:【单调栈】

图1
通过观察图像,我们可以发现红色方框部分与木桶的形态颇为相似。让我们富有想象力地将最左侧高度为2的柱子视作木桶的左侧板,而将最右侧高度为3的柱子视作木桶的右侧板。基于深入人心的【木桶原理】,一个木桶的装水量总是受限于其最短的那块木板 ==> 若能在上图中探寻到所有“有效的”木桶,并计算这些木桶的装水量再进行汇总,我们便能获得所求的结果。

问题1:如何获取所有“有效的”木桶呢?

首先,对木桶的组成部分有个清晰的定义:木桶分为【左侧板】【底板】和【右侧板】三个部分。
在这里插入图片描述
通过观察图像,我们可以发现,从左到右遍历height数组时,柱子高度会呈现出一种特殊的规律。首先,从左侧板到底板的过程中,柱子高度会逐渐降低,形成一个递减的趋势。接着,从底板到右侧板的过程中,柱子高度则会逐渐升高,形成一个递增的趋势。更为有趣的是,图像中多次出现了这种“递减-递增”的模式转换,每一次的转换都可能构成一个“有效的”木桶。这种观察不仅揭示了数据背后的隐藏规律,也为我们解决问题提供了新的视角和思路。

问题2:如何捕捉到这种“递减-递增”的模式转换呢?

使用单调栈

要捕捉这种递减-递增的模式转换,我们可以使用单调栈。单调栈是一种数据结构,它能够保持栈内元素按照特定的顺序排列。在这个问题中,我们可以使用一个单调递减栈stack来存储数组 height下标。 ==> 用单调栈存储潜在的【左侧板】和【底板】

细节1: 之所以选择存储元素的“下标”,是为了方便计算“有效”木桶的宽度。通过存储下标,我们可以轻松地获取到木桶的左侧板、底板和右侧板的位置,从而计算出木桶的宽度。

从左往右遍历height数组,如果新的元素height[i]比栈顶元素height[stack[-1]]还大 ⇒ 不满足递减 ⇒ 出现了右侧板,那么此时的栈顶下标top=stack.pop()表示的就是“桶底”,而栈顶元素height[top]表示底板距离地面(柱子高度为0视为地面)的高度;倘若stack中存储不止一个下标,那么弹出栈顶下标top后,stack一定非空 ⇒ 新的栈顶下标left=stack[-1]表示的就是“左侧板”所在位置,而新的栈顶元素height[left]表示左侧板的高度**。当“底板”和“左侧板”都存在时,说明存在“有效木桶”,那么新的元素下标i可以用变量right进行表征,即right=i,表示右侧板所在位置。那么Width = right - left - 1即为木桶的有效宽度

在这里插入图片描述

细节2: 之所以说栈顶元素height[top]表示底板距离地面的高度是因为每个底板不一定都在地面上。因此,根据木桶原理,木桶的有效高度Height = min(height[left],height[right]) - height[top] ⇒ 该木桶容纳水的含量 water = Height * Width

细节3: 在某些区域,可能会有多个木桶。就像上图所示,红色框代表的大木桶下面,还隐藏着一个绿色框代表的小木桶。根据我们的生活常识,当给这两个叠在一起的木桶装水时,首先装满的一定是小木桶。当小木桶装满水后,我们可以将小木桶当作大木桶的底板(小木桶的左侧板当作大木桶的底板,可和代码结合理解),继续给大木桶装水。而基于【单调栈】的解法,正好与我们的常识保持一致。

完整代码

class Solution:
    def trap(self, height: List[int]) -> int:
        total_water = 0 # 记录水的容量
        stack = list() # 创建单调递减栈
        n = len(height)
        
        for i, h in enumerate(height): # 遍历数组height的每个元素
        	# 当栈非空 且 新的元素h比栈顶元素height[stack[-1]]还大时 
            while stack and h > height[stack[-1]]: 
                right = i # 找到右侧板,用变量right进行表征
                top = stack.pop() # 栈顶下标表示底板,不可能在表示左侧板,更不可能是右侧板 ---> 直接弹出
                if not stack: # 栈空 --> 没有找到左木板,不能组成有效的木桶
                    break # 跳出while循环 寻找下一个右木板
                else: # 找到左木板
                    left = stack[-1] # 当前栈顶表示左木板的下标可能会作为下一个有效木桶的底板 --> 不能弹出 
                    if height[left] == height[top]:
                        # 左木板高度和底板高度一致 ---> 根据木板原理,装不下任何水
                        continue # 固定右侧板,寻找下一个有效木桶
                    else: 
                        # height[top] < height[left]  且  height[top] < height[right] 恒成立
                        # 这个木桶一定能装到水
                        bucket_width = right - left - 1
                        bucket_height = min(height[left], height[right]) - height[top]
                        total_water += bucket_width * bucket_height
            # 当前扮演右木板 --> 接着可能会扮演左木板/桶底
            stack.append(i)
   
        return total_water

运行结果
在这里插入图片描述

复杂度分析

  • 时间复杂度:O(N),其中 N 是数组height元素的数量。
    • 外层for循环遍历数组 height ===> O(N)
    • 内层while循环中, height每个元素最多出/入栈一次 ===> O(1)
  • 空间复杂度:O(N)
    • 栈空间元素个数不会超过N ===> O(N)

结束语

  • 亲爱的读者,感谢您花时间阅读我们的博客。我们非常重视您的反馈和意见,因此在这里鼓励您对我们的博客进行评论。
  • 您的建议和看法对我们来说非常重要,这有助于我们更好地了解您的需求,并提供更高质量的内容和服务。
  • 无论您是喜欢我们的博客还是对其有任何疑问或建议,我们都非常期待您的留言。让我们一起互动,共同进步!谢谢您的支持和参与!
  • 我会坚持不懈地创作,并持续优化博文质量,为您提供更好的阅读体验。
  • 谢谢您的阅读!

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

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

相关文章

总线地址/物理地址/虚拟地址

参考&#xff1a; 总线地址、物理地址、虚拟地址-CSDN博客 内存管理&#xff1a;物理地址、虚拟地址、逻辑地址_虚拟地址和物理地址-CSDN博客 总线地址 总线地址和地址总线是一个概念。地址总线 (Address Bus&#xff1b;又称&#xff1a;位址总线) 属于一种电脑总线 &#xf…

React和umi搭建项目的操作步骤

​​​​​​一、react脚手架新建项目 (1.1)、命令行 前提&#xff1a;react ES2015,nodejs v8 npx create-react-app myReactName //2022年v16以下版本 myReactName(自定义项目名) react中文官网&#xff0c;快速上手&#xff1a;react中文官网 react框架&#xff0c;…

Linux系统中查看路由表的命令(ip route)

以下命令是在Linux系统中查看路由表的命令&#xff1a; 在Linux系统中&#xff0c;有多种方法可以查看路由设置。以下是一些常用的命令&#xff1a; ip route 或 ip -4 route&#xff08;IPv4&#xff09;/ ip -6 route&#xff08;IPv6&#xff09;&#xff1a; 这是最常用且功…

算法设计与分析期末知识点总结

一、概论 1、算法设计的目标&#xff1a; &#xff08;1&#xff09;正确性 &#xff08;2&#xff09;可使用性&#xff08;用户友好性&#xff09; &#xff08;3&#xff09;可读性 &#xff08;4&#xff09;健壮性 &#xff08;5&#xff09;高效率与低存储量需求 算…

vue 快速入门+vite前端构建工具

四、Vue3简介和快速体验 4.1 Vue3介绍 Vue (发音为 /vjuː/&#xff0c;类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高效地开发用户界面。无论是简…

迪文屏开发保姆级教程——页面键盘

迪文屏页面键盘保姆级教程。 本篇文章主要介绍了在DGBUS平台上使用页面键盘的步骤。 文章目录 一、前言 开发环境 二、使用步骤 1.准备素材 2.打开DGUS工程&#xff0c;导入素材。 3.生成ICL文件。 4.添加数据变量显示控件 5.添加数据录入控件 A.变量地址设置 B.变量类…

外媒发稿最好的宣传方法是什么?大舍传媒

外媒发稿最好的宣传方法是什么&#xff1f; 引言 在如今信息爆炸的时代&#xff0c;外媒发稿的宣传方法至关重要。大舍传媒作为一家业内知名的传媒公司&#xff0c;积累了丰富的经验和成功案例。本文将探讨外媒发稿最好的宣传方法&#xff0c;旨在帮助读者更好地推广自己的信…

将输入的文本包装成多个行使每行的字符数不超过指定的列宽textwrap.fill()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 将输入的文本包装成多个行 使每行的字符数不超过指定的列宽 textwrap.fill() [太阳]选择题 请问以下代码每行最多能输出字符数是&#xff1f; import textwrap text "This is a long …

(PC+WAP)装修设计公司网站模板 家装公司网站源码下载

(PCWAP)装修设计公司网站模板 家装公司网站源码下载 PbootCMS内核开发的网站模板&#xff0c;该模板适用于装修设计、家装公司类等企业&#xff0c;当然其他行业也可以做&#xff0c;只需要把文字图片换成其他行业的即可&#xff1b; PCWAP&#xff0c;同一个后台&#xff0c…

【Redis】四、Redis.conf详解

文章目录 Redis.conf详解单位网络通用 GENERAL快照REPLICATION 复制SECURITY 安全限制 CLIENTSAPPEND ONLY 模式 aof配置 Redis.conf详解 启动的时候&#xff0c;就通过配置文件来启动&#xff01; 工作中&#xff0c;一些小小的配置&#xff0c;可以让你脱颖而出&#xff01;…

多域名证书和通配符证书的区别?

先来说说多域名证书&#xff08;别急&#xff0c;通配符证书&#xff0c;马上就有戏&#xff09;。多域名证书&#xff0c;正式的名字叫主题备用名称&#xff08;SAN&#xff09;证书。想象一下&#xff0c;它们就像是一个超级英雄联盟&#xff0c;能在一个SSl证书下保护包含不…

《Linux C编程实战》笔记:进程操作之退出,执行,等待

进程退出 进程退出表示进程即将运行结束。在Linux中退出分为正常退出和异常退出。 正常退出&#xff1a; 在main函数中执行return调用exit函数调用_exit函数 异常退出&#xff1a; 调用abort函数收到某个信号&#xff0c;这个信号是程序终止 退出方式比较 exit和return的…

「Verilog学习笔记」游戏机计费程序

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 timescale 1ns/1nsmodule game_count(input rst_n, //异位复位信号&#xff0c;低电平有效input clk, //时钟信号input [9:0]money,input set,input boost,output reg[9:0…

工业缺陷检测新时代!OpenCV4六种方法助你轻松应对生产难题!

OpenCV4工业缺陷检测的六种方法 机器视觉缺陷检测好书推荐工业上常见缺陷检测方法方法一&#xff1a;方法二&#xff1a;方法三&#xff1a;方法四&#xff1a;方法五&#xff1a;方法六&#xff1a; 写在末尾&#xff1a; 主页传送门&#xff1a;&#x1f4c0; 传送 送书系列…

Module build failed: TypeError: this.getOptions is not a function

在使用webpack打包出现以上错误时&#xff0c;可能是你安装的css-loader和style-loader的版本过高。 我用的webpack版本是3.6.0 因此需要降低一下版本 在你编辑器终端输入以下命令&#xff1a; npm install css-loader3.6.0 npm install --save-dev style-loader1.00 然后接下…

八大易犯领英LinkedIn错误

领英是一个全球知名的职场社交平台&#xff0c;拥有海量的用户&#xff0c;也成为了外贸人开发客户的一个重要平台。但是如果没有很好地避好一些易犯错误&#xff0c;那很可能努力的结果是事倍功半。接下来我来讲解八大容易犯的领英错误。 1、没有完善个人信息 领英是一个职场…

基于单片机的智能小车 (论文+源码)

1. 系统设计 此次可编程智能小车系统的设计系统&#xff0c;结合STM32单片机&#xff0c;蓝牙模块&#xff0c;循迹模块&#xff0c;电机驱动模块来共同完成本次设计&#xff0c;实现小车的循迹避障功能和手机遥控功能&#xff0c;其整体框架如图2.1所示。其中&#xff0c;采用…

淘宝类目信息API接口获取淘宝商品分类信息API调用说明(含APIkey密钥)

cat_get-获得淘宝分类详情 item_cat_get-获得淘宝商品类目 公共参数 名称类型必须描述keyString是调用key&#xff08;点此获取&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_search_…

【web安全】密码爆破讲解,以及burp的爆破功能使用方法

前言 菜某总结&#xff0c;欢迎指正错误进行补充 密码暴力破解原理 暴力破解实际就是疯狂的输入密码进行尝试登录&#xff0c;针对有的人喜欢用一些个人信息当做密码&#xff0c;有的人喜欢用一些很简单的低强度密码&#xff0c;我们就可以针对性的生成一个字典&#xff0c;…

配置https环境

为什么要配置https环境 在使用 HTML5 的 API 时&#xff0c;很多 API 只能在 https 保证安全的情况下才能开启。这就要求我们在本地开发环境也能够配置 https&#xff0c;否则你需要每次部署到配有 https 的测试环境中才能看到预览效果&#xff0c;这对开发的敏捷度造成了极大…