【LeetCode刷题笔记(8-3)】【Python】【接雨水】【双指针】【困难】

文章目录

  • 引言
  • 接雨水
    • 题目描述
    • 提示
  • 解决方案3:【双指针】
  • 结束语

接雨水

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

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

引言

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

接雨水

题目描述

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

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

提示

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

解决方案3:【双指针】

在【LeetCode刷题笔记(8-1)】【Python】【接雨水】【动态规划】【困难】和【LeetCode刷题笔记(8-2)】【Python】【接雨水】【单调栈】【困难】中,我们详细阐述了如何在一步步理性分析下基于【动态规划】和【单调栈】设计完整的算法和代码通过接雨水的所有测试用例。这两种算法的空间复杂度都是O(n),其中动态规划法需要额外维护两个长度为N的数组left_max_listright_max_list,用于记录每个位置i ,其左侧柱子的最大高度left_max_list[i]和右侧柱子的最大高度right_max_list[i]

具体来说,我们首先从左到右完整地遍历数组height得到left_max_list,然后再从右往左完整地遍历数组height得到right_max_list。实际上,这相当于把【接雨水】问题的解决策略分成两个相对独立的步骤:

  1. 获取每个位置i ,其左侧和右侧柱子的最大高度。这一步需要两个for循环,分别从左到右和从右到左遍历数组。

  2. 根据木桶原理,以及步骤1获取的必要信息,得到最终的雨水总量。这一步还需要一个for循环,遍历整个数组。

问题1:有没有其它策略能够把步骤一和步骤二结合起来,即在一个循环下解决【接雨水】问题?

有,双指针。

在上面的分析过程中,我们发现步骤1的两个循环,一个是从左往右,一个是从右往左,这种遍历方法和双指针非常类似。因此,我们考虑是否可以用左指针替代从左往右的循环,同时用右指针替代从右往左的循环。这样,我们可以在一次遍历中完成两个步骤,提高算法的效率。

不仅可以,而且还买一送一,顺带解决了获取位置i雨水量的问题。

1. 当左指针left从左往右的移动过程中,我们可以通过left_max记录区间[0,left]的最大高度 。同理,当右指针right从右往左的移动过程中,我们也可以通过right_max记录区间[right,n-1]的最大高度。

关键问题2:如何决定下一步是移动左指针还是右指针?

当能确定位置left的接水量时,left右移;当能确定位置right的接水量时,right左移;

对于当前左指针的位置left,[0, left]区间的最大高度left_max是已知的,并且[right,n-1]区间的最大高度right_max也是已知的。根据木板原理,一个木桶的装水量总是受限于其最短的那块木板 ⇒ 此时left_max<right_max成立 ⇒ [0, left]的最高左木板 < [right, n-1]区间的最高右木板 <= [left+1, n-1]区间的最高右木板 恒成立⇒ 位置left的装水量由[0, left]的最高左木板决定,而[0, left]的最高左木板已经是板上钉钉 ⇒ 自然可以计算位置left的接水量water_left = left_max - height[left];既然位置left的接水量已经确定,下一步自然是left右移。

同理,对于当前右指针的位置right,[0, left]区间的最大高度left_max是已知的,并且[right,n-1]区间的最大高度right_max也是已知的 ⇒ 此时right_max < left_max成立 ⇒ [right, n-1]区间的最高右木板 < [0, left]的最高左木板 <= [0,right-1]区间的最高左木板 恒成立⇒ 位置right的装水量由 [right, n-1]区间的最高右木板决定,而 [right, n-1]区间的最高右木板的值已经是板上钉钉 ⇒ 自然可以计算位置right的接水量water_right = right_max - height[right];既然位置right的接水量已经确定,下一步自然是right左移。

完整代码如下

class Solution:  
    def trap(self, height: List[int]) -> int:  
        # 初始化结果为0  
        total_water = 0  
        # left指向数组的起始位置  
        left = 0  
        # right指向数组的末尾位置  
        right = len(height) - 1  
        # left_max记录从左到left的最大高度  
        left_max = 0  
        # right_max记录从right到数组末尾的最大高度  
        right_max = 0  
    
        # 当left小于right时,持续进行以下操作  
        while left < right:  
            # 更新left_max为当前left位置的高度和left_max中的较大值  
            left_max = max(left_max, height[left])  
            # 更新right_max为当前right位置的高度和right_max中的较大值  
            right_max = max(right_max, height[right])  
                
            if left_max < right_max:  
                # left_max小于right_max ==> 依据木桶原理 ==> 位置left雨水量由左木板最大高度和位置left的柱子高度共同确定  
                total_water += left_max - height[left]  
                # 向右移动left  
                left += 1  
            else:  
                # right_max大于等于left_max ==> 依据木桶原理 ==> 位置right的雨水量由左木板最大高度和位置left的柱子高度共同确定  
                total_water += right_max - height[right]  
                # 向左移动right  
                right -= 1  
            
        # 返回最终的雨水量  
        return total_water

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

复杂度分析

  • 时间复杂度:O(N),其中 N 是数组height元素的数量。
  • 空间复杂度:O(1)
    • 利用双指针动态记录区间[0, left] 和[right, N-1]的最大值 ===> O(1)

结束语

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从如何使用到如何实现一个Promise

promise是什么&#xff1f;主要用来解决什么问题&#xff1f; Promise是异步编程的一种解决方案&#xff0c;比传统解决方案--回调函数和事件--更合理更强大。 Promise特点&#xff1a; &#xff08;1&#xff09;对象的状态不受外界影响。Promise对象代表一个异步操作&…

ModuleNotFoundError: No module named ‘openai.error‘

ModuleNotFoundError: No module named ‘openai.error’ result self.fn(*self.args, **self.kwargs) File “H:\chatGPTWeb\chatgpt-on-wechat\channel\chat_channel.py”, line 168, in _handle reply self._generate_reply(context) File “H:\chatGPTWeb\chatgpt-on-wec…

2023_Spark_实验二十九:Flume配置KafkaSink

实验目的&#xff1a;掌握Flume采集数据发送到Kafka的方法 实验方法&#xff1a;通过配置Flume的KafkaSink采集数据到Kafka中 实验步骤&#xff1a; 一、明确日志采集方式 一般Flume采集日志source有两种方式&#xff1a; 1.Exec类型的Source 可以将命令产生的输出作为源&…

性能加速包: SpringBoot 2.7JDK 17,你敢尝一尝吗 | 京东物流技术团队

前言 众所周知&#xff0c;SpringBoot3.0迎来了全面支持JDK17的局面&#xff0c;且最低支持版本就是JDK17&#xff0c;这就意味着&#xff0c;Spring社区将完全抛弃JDK8&#xff0c;全面转战JDK17。作为JAVA开源生态里的扛把子&#xff0c;Spring可以说是整个JAVA生态的风向标…

(8)Linux Makefile | 依赖关系,依赖方法

&#x1f4ad;前言&#xff1a; 本篇文章会着重讲解Linux中的自动化构建代码工具: make/makefile的介绍与使用。 在Linux下编译代码时,每次都会输入 gcc code.c -o code.exe在删除可执行程序时,每次都会输入 rm -rf code.exe这样非常的不方便,很麻烦,于是乎学习自动化构建代…

原来Python的协程有2种实现方式

什么是协程 在 Python 中&#xff0c;协程&#xff08;Coroutine&#xff09;是一种轻量级的并发编程方式&#xff0c;可以通过协作式多任务来实现高效的并发执行。协程是一种特殊的生成器函数&#xff0c;通过使用 yield 关键字来挂起函数的执行&#xff0c;并保存当前的执行…

《Effective C++》学习笔记 续

条款31&#xff1a;将文件间编译依存关系降至最低 请记住&#xff1a; 支持”编译依存性最小化“的一般构想是&#xff1a;相依于声明式&#xff0c;不要相依于定义式。基于此构想的两个手段是Handle class和Interface class程序库头文件应该以”完全且仅有声明式“的形式存在…

uniapp 用于开发H5项目展示饼图,使用ucharts 饼图示例

先下载ucharts H5示例源码&#xff1a; uCharts: 高性能跨平台图表库&#xff0c;支持H5、APP、小程序&#xff08;微信小程序、支付宝小程序、钉钉小程序、百度小程序、头条小程序、QQ小程序、快手小程序、360小程序&#xff09;、Vue、Taro等更多支持canvas的框架平台&#…

网络安全之Linux环境配置及Linux基础知识讲解<三>

目录 一.下载安装Vmware二.下载安装Kali三.Linux目录结构四.Linux文件属性五.文件目录管理六.vim编辑器 一.下载安装Vmware Vmware官网&#xff1a;https://www.vmware.com 二.下载安装Kali Kali包含数百种工具&#xff0c;可用于各种信息安全任务&#xff0c;例如渗透测试、…

(C++)将x减到0的最小操作数--滑动窗口

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能&#xff0c;轻松拿下世界 IT 名企 Dream Offer。https://le…

微机总线地址物理内存地址虚拟内存地址简介

硬件地址的相关概念 Raspberry Pi 发布适用于 ARM 外设的 BCM2835 数据表 地址映射 总线地址 物理地址 虚拟地址 页表和内存管理单元MMU 《 Linux内核设计与实现&#xff08;第三版&#xff09;》 树莓派博通BCM2835芯片手册 硬件地址的相关概念 总线地址 32位的操作系统 &…

【赠书活动】OpenCV4工业缺陷检测的六种方法

文章目录 前言机器视觉缺陷检测工业上常见缺陷检测方法延伸阅读推荐语 赠书活动 前言 随着工业制造的发展&#xff0c;对产品质量的要求越来越高。工业缺陷检测是确保产品质量的重要环节&#xff0c;而计算机视觉技术的应用能够有效提升工业缺陷检测的效率和精度。 OpenCV是一…

【机器学习】卷积神经网络(CNN)的特征数计算

文章目录 基本步骤示例图解过程 基本步骤 在卷积神经网络&#xff08;CNN&#xff09;中&#xff0c;计算最后的特征数通常涉及到以下步骤&#xff1a; 确定输入尺寸&#xff1a; 首先&#xff0c;你需要知道输入数据的尺寸。对于图像数据&#xff0c;这通常是 (batch_size, c…

1-完全理解以太坊智能合约

了解区块链 区块链技术的核心概念是分布式账本&#xff0c;它是许多参与者共享的特定类型的数据库。 这个特殊的数据库只是一个交易列表&#xff0c;记录着网络中发生的每笔交易。每个人都可以拥有自己的交易列表备份&#xff0c;再加上强有力的货币激励措施消除各方之间信任…

记录今日将C语言的Windows程序更改为python语言Windows程序,实现子窗口控制,类似微信程序框架最简单的原型

基本思路 为什么要选择python制作Windows应用程序&#xff0c;主要就是源代码直接展示&#xff0c;发现问题随时修改&#xff0c;同时可以不断增加新的功能方便。 由于C语言的Windows程序中结构类型在python中不能使用&#xff0c; 因此我们按照ctypes模块指导意见继承structu…

基于双目RGB图像和图像深度信息的三维室内场景建模matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 双目视觉原理 4.2 深度信息获取 4.3 表面重建 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 .....................................…

STM32与Freertos入门(三)任务的创建、删除

1、串口配置 首先将串口进行配置&#xff0c;后续经常会应用&#xff0c;具体步骤点击&#xff1a;串口配置。 2、任务 创建一个任务&#xff0c;就是开辟一个空间、每个任务中都会有while&#xff08;1&#xff09;死循环。 2.1相关函数 动态创建&#xff1a;xTaskCreate…

ros2/ros 4轮2驱机器人xacro/urdf文件示例代码

这个实验中最重要的是&#xff1a;colcon build 之后要记得source install/setup.bash.否则修改的文件是不会更新的。知道了吧 <robot name"half" xmlns:xacro"http://wiki.ros.org/wiki/xacro"><xacro:property name"PI" value"3…

SL3041高耐压100V降压恒压芯片 24V降压5V 24V降压12V 12V降5V

SL3041宽电压100V恒压芯片 24V降压5V 24V降压12V SL3041是一款宽电压100V恒压芯片&#xff0c;具有高效率、高精度、高可靠性等优点&#xff0c;广泛应用于各种电源系统中。在本文中&#xff0c;我们将详细介绍SL3041的工作原理、应用场景以及如何使用它实现24V降压5V和24V降压…

无框架Java转go语言写http与tcp请求

项目地址 https://github.com/cmdch2017/http_tcpServer 项目结构 如何快速上手 http篇 1、controller包就相当于RestController&#xff0c;这里返回了一个Person对象&#xff0c;当你需要新建一个接口时&#xff0c;再新写一个func仿照下面的方法就行了 package control…