【面试经典 150 | 数组】接雨水

文章目录

  • 写在前面
  • Tag
  • 题目来源
  • 解题思路
    • 方法一:预处理
    • 方法二:单调栈
    • 方法三:双指针
  • 写在最后

写在前面

本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更……

专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行回顾与总结,文章结构大致如下,部分内容会有增删:

  • Tag:介绍本题牵涉到的知识点、数据结构;
  • 题目来源:贴上题目的链接,方便大家查找题目并完成练习;
  • 题目解读:复述题目(确保自己真的理解题目意思),并强调一些题目重点信息;
  • 解题思路:介绍一些解题思路,每种解题思路包括思路讲解、实现代码以及复杂度分析;
  • 知识回忆:针对今天介绍的题目中的重点内容、数据结构进行回顾总结。

Tag

【数组】【单调栈】【双指针】


题目来源

42. 接雨水


解题思路

方法一:预处理

思路

一个朴素的做法是对于数组 height 中的每个元素,分别向左和向右扫描并记录左边的最大高度,然后计算每个下标位置能接到的雨水量。

假设数组 height 的长度为 n n n,朴素的做法需要对每个下标位置使用 O ( n ) O(n) O(n) 的时间向两边扫描并获得最大高度,总的时间复杂度为 O ( n 2 ) O(n^2) O(n2)

本题数据规模达到 1 0 5 10^5 105,时间复杂度为 O ( n 2 ) O(n^2) O(n2) 的解法一定超时。

预处理

上述做法的时间复杂度较高是因为需要对每个下标位置都向两边扫描。如果已经知道每个位置两边的最大高度,则可以在 O(n)O(n)O(n) 的时间内得到能接的雨水总量。

于是可以提前计算并记录每个位置两侧的最大高度。

具体地,维护数组 leftMaxrightMax,其中 leftMax[i] 表示下标 i 及其左边的位置中,height 的最大高度。rightMax[i] 表示下标 i 及其右边的位置中,height 的最大高度。显然有初始化 leftMax[0] = height[0]rightMax[n-1] = height[n-1],其余位置的元素计算比较简单,直接看代码。

代码

class Solution {
public:int trap(vector<int>& height) {int n = height.size();if (n == 0) {return 0;}// 更新 leftMaxvector<int> leftMax(n);leftMax[0] = height[0];for (int i = 1; i < n; ++i) {leftMax[i] = max(leftMax[i-1], height[i]);}// 更新 rightMaxvector<int> rightMax(n);rightMax[n-1] = height[n-1];for (int i = n - 2; i >= 0; --i) {rightMax[i] = max(rightMax[i+1], height[i]);}int res = 0;for (int i = 0; i < n; ++i) {res += min(leftMax[i], rightMax[i]) - height[i];}return res;}
};

复杂度分析

时间复杂度: O ( n ) O(n) O(n)

空间复杂度: O ( n ) O(n) O(n)

方法二:单调栈

思路

除了计算并存储每个位置两边的最大高度以外,也可以用单调栈计算能接的雨水总量。

维护一个单调栈,单调栈存储的是下标,满足从栈底到栈顶的下标对应的数组 height 中的元素递减。

从左到右遍历数组,遍历到下标 i 时,如果栈内至少有两个元素,记栈顶元素为 toptop 的下面一个元素是 left,则一定有 height[left]≥height[top]。如果 height[i]>height[top],则得到一个可以接雨水的区域,该区域的宽度是 i−left−1,高度是 min⁡(height[left],height[i])−height[top],根据宽度和高度即可计算得到该区域能接的雨水量。

为了得到 left,需要将 top 出栈。在对 top 计算能接的雨水量之后,left 变成新的 top,重复上述操作,直到栈变为空,或者栈顶下标对应的 height 中的元素大于或等于 height[i]

在对下标 i 处计算能接的雨水量之后,将 i 入栈,继续遍历后面的下标,计算能接的雨水量。遍历结束之后即可得到能接的雨水总量。

代码

class Solution {
public:int trap(vector<int>& height) {int n = height.size(), res = 0;stack<int> stk;for (int i = 0; i < n; ++i) {while (!stk.empty() && height[i] > height[stk.top()]) {int top = stk.top(); stk.pop();if (stk.empty()) {break;}int left = stk.top();int curWidth = i - left - 1;int curHeigh = min(height[left], height[i]) - height[top];res += curWidth * curHeigh;}stk.push(i);}return res;}
};

复杂度分析

时间复杂度: O ( n ) O(n) O(n) n n n 是数组 height 的长度。从 0 到 n-1 的每个下标最多只会入栈和出栈一次。

空间复杂度: O ( n ) O(n) O(n)。空间复杂度主要取决于栈空间,栈的大小不会超过 n。

方法三:双指针

思路

下标 i 处能接的雨水量由 leftMax[i]rightMax[i] 中的最小值决定。数组 leftMax 是从左到右计算的,数组 rightMax 是从右到左计算的,我们可以使用双指针和两个变量来代替两个数组。

使用 height[left]height[right] 来更新 leftMaxrightMax 比较容易理解就不说了。重点说一下如何更新 res

  • height[left] < heigh[right] 时,必有 leftMax < rightMax,下标 left 处一定可以盛水;
  • height[left] >= heigh[right] 时,必有 leftMax >= rightMax,下标 right 处一定可以盛水。

代码

class Solution {
public:int trap(vector<int>& height) {int res = 0;int left = 0, right = height.size() - 1;int leftMax = 0, rightMax = 0;while (left < right) {leftMax = max(leftMax, height[left]);rightMax = max(rightMax, height[right]);if (height[left] < height[right]) {res += leftMax - height[left++]; }else {res += rightMax - height[right--];}}return res;}
};

复杂度分析

时间复杂度: O ( n ) O(n) O(n) n n n 为数组 height 的长度。

空间复杂度: O ( 1 ) O(1) O(1)


写在最后

如果您发现文章有任何错误或者对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

如果大家有更优的时间、空间复杂度的方法,欢迎评论区交流。

最后,感谢您的阅读,如果有所收获的话可以给我点一个 👍 哦。

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

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

相关文章

AI大模型日报#0430:疑似GPT4.5模型刷屏、上交实现「蛋白质功能定向进化」、微软紧急撤回WizardLM-2

导读&#xff1a; 欢迎阅读《AI大模型日报》&#xff0c;内容基于Python爬虫和LLM自动生成。目前采用“文心一言”生成了今日要点以及每条资讯的摘要。 《AI大模型日报》今日要点&#xff1a; 在AI大模型领域&#xff0c;多项研究进展和行业应用动态引发关注。一夜之间&#x…

Opencv_14_多边形填充与绘制

绘制多边形&#xff1a; 1&#xff09;coInvert.polyline_drawing(src); 2&#xff09;void ColorInvert::polyline_drawing(Mat& image) { Mat canvas Mat::zeros(Size(512, 512), CV_8UC3); Point p1(100, 100); Point p2(150, 100); Point p3(200…

vue3 安装-使用之第一篇

首先需要node版本高于V16.14.1 安装 执行 npm create vitelatest 具体选择按照自己实际需要的来 Project name:项目名称 Select a framework:选择用哪种框架 &#xff08;我选择vue&#xff09; Select a variant: 选择用JS还是TS&#xff08;我选择JS&#xff09;找到项目&…

kotlinDSL控制的安卓项目导入已存在的模块后sync报错

原因很明显&#xff0c;但是我还找了好久 因为在import时并没有选择groove还是kotlin控制&#xff0c; 所以默认为groovy控制的&#xff0c;然而主项目是由kotlin dsl控制的grale行为。 原因清楚之后&#xff0c;就可以去检查一下&#xff0c;项目里是否包含了settings.gradle和…

rk3588部署yolov8视频目标检测教程

1. 环境配置 1.1 训练和导出onnx环境 #使用conda创建一个python环境 conda create -n torch python3.9#激活环境 conda activate torch#安装yolov8 pip install ultralytics -i https://pypi.tuna.tsinghua.edu.cn/simple 1.2 导出rknn环境 安装toolkit2-1.5.2 下载链接&am…

使用 LlamaIndex 和 Llama 2-Chat 构建知识驱动的对话应用程序

文章目录 使用 LlamaIndex 和 Llama 2-Chat 构建知识驱动的对话应用程序Llama 2-70B-聊天LlamaIndex 解决方案概述先决条件使用 SageMaker JumpStart 部署 GPT-J 嵌入模型使用 SageMaker Python SDK 进行部署在 SageMaker Studio 中使用 SageMaker JumpStart 进行部署使用 Sage…

如何查看我的Docker 容器和 `app.py` 脚本有足够的权限来读取 `config.json` 文件

要检查 Docker 容器和 app.py 脚本是否具有读取 config.json 文件的足够权限&#xff0c;你可以按照以下步骤操作&#xff1a; 检查宿主机上的文件权限&#xff1a; 在宿主机上&#xff0c;使用 ls -l 命令查看 config.json 文件的权限。 ls -l /path/to/config.json确保该文件…

聊聊Mysql的两阶段提交

从图中可看出&#xff0c;事务的提交过程有两个阶段&#xff0c;就是将 redo log 的写入拆成了两个步骤&#xff1a;prepare 和 commit&#xff0c;中间再穿插写入bin log&#xff0c;具体如下&#xff1a; prepare 阶段&#xff1a;将 事务的修改写入到 redo log&#xff0c;同…

Java | Leetcode Java题解之第62题不同路径

题目&#xff1a; 题解&#xff1a; class Solution {public int uniquePaths(int m, int n) {long ans 1;for (int x n, y 1; y < m; x, y) {ans ans * x / y;}return (int) ans;} }

设计模式-01 设计模式单例模式

设计模式-01 设计模式单例模式 目录 设计模式-01 设计模式单例模式 1定义 2.内涵 3.使用示例 4.具体代码使用实践 5.注意事项 6.最佳实践 7.总结 1 定义 单例模式是一种设计模式&#xff0c;它确保一个类只能被实例化一次。它通过在类内部创建类的唯一实例并提供一个全…

Mysql从入门到精通——Mysql知识点总结(基础篇)

参考视频 黑马程序员 MySQL数据库入门到精通i 题单推荐 入门 进阶 SQL语句类型 DDL:数据定义语言&#xff0c;用来定义数据库对象(数据库&#xff0c;表&#xff0c;字段)DML:数据操作语言&#xff0c;对数据库表中的数据进行增删改DQL:数据查询语言,用来查询数据库中表的…

SpringCloud 学习笔记 —— 六、Ribbon:负载均衡(基于客户端)

SpringCloud 学习笔记 —— 一、背景-CSDN博客 SpringCloud 学习笔记 —— 二、微服务与微服务架构-CSDN博客 SpringCloud 学习笔记 —— 三、SpringCloud 入门概述-CSDN博客 SpringCloud 学习笔记 —— 四、SpringCloud Rest 学习环境搭建&#xff1a;服务提供者-CSDN博客 …

一站式AI创作平台:融合GPT会话、GPTs应用、Midjourney视觉艺术与Suno AI音乐合成模块

一、系统简介 星河易创AI系统基于ChatGPT的核心技术打造&#xff0c;集成了自然语言问答和艺术创作功能。该系统兼容Midjourney绘画技术&#xff0c;并支持官方GPT模型。它提供了多样化的应用&#xff0c;包括GPTs的多场景应用、实时GPT语音对话能力、GPT-4模型的先进特性&…

全网最全的springboot配置文件速成

文章目录 一.配置文件格式前言1.1 application.properties配置文件1.2 application.yml配置文件1.3 application.yaml配置文件1.4 在配合文件中如果没有提示1.5 三种配合文件的优先级 二. yml格式2.1 优点2.2 YAML 文件扩展名2.3 语法规则2.4 配置 三. 配置文件数据读取3.1 环境…

Sarcasm detection论文解析 |用于微博讽刺检测的上下文增强卷积神经网络

论文地址 论文地址&#xff1a;Context-augmented convolutional neural networks for twitter sarcasm detection - ScienceDirect 论文首页 笔记大纲 用于微博讽刺检测的上下文增强卷积神经网络 &#x1f4c5;出版年份:2018 &#x1f4d6;出版期刊:Neurocomputing &#x1f…

工业互联网通讯协议—欧姆龙(Fins tcp)

一、场景 近期公司要对欧姆龙CP系列设备的数据采集&#xff0c;于是就研究了下欧姆龙的Fins Tcp协议。 二、Fins Tcp 组成字节说明固定头446494E53 FINS对应的ASCII码的十六进制长度4后面剩余指令的长度命令4 握手固定为&#xff1a;00000000 读写固定为&#xff1a;0000000…

Fast Bilateral Filteringfor the Display of High-Dynamic-Range Images

1 Title Fast Bilateral Filtering for the Display of High-Dynamic-Range Images(Fredo Durand and Julie Dorsey)【SIGGRAPH 02】 2 Conclusion This paper presents a new technique for the display of high-dynamic-range images, which reduces the contrast while pre…

(详细整理!!!!)Tensorflow与Keras、Python版本对应关系!!!

小伙伴们大家好&#xff0c;不知道大家有没有被tensorflow框架困扰过 今天我就给大家整理一下tensorflow和keras、python版本的对应关系 大家这些都可以在官网找到&#xff0c;下面我把官网的连接给大家放在这里&#xff1a;在 Windows 环境中从源代码构建 | TensorFlow (g…

学习 Rust 第 23 天:闭包

Rust 闭包提供了简洁、富有表现力的匿名函数来捕获周围的变量。它们简化了代码&#xff0c;提供了存储、参数传递和函数重构方面的灵活性。它们与泛型的交互增强了灵活性&#xff0c;而捕获模式则促进了有效的所有权和可变性管理。从本质上讲&#xff0c;闭包是 Rust 的基础&am…

Docker部署RabbitMQ与简单使用

官网地址&#xff1a; Messaging that just works — RabbitMQ 我的Docker博客:Docker-CSDN博客 1.结构 其中包含几个概念&#xff1a; **publisher**&#xff1a;生产者&#xff0c;也就是发送消息的一方 **consumer**&#xff1a;消费者&#xff0c;也就是消费消息的一方 …