每日一题——接雨水
接雨水问题详解
视频学习推荐
建议先参考以下视频进行学习:
问题描述
给定一个非负整数数组 height,表示每个宽度为 1 的柱子的高度图。计算按此排列的柱子,下雨之后能接多少雨水。
示例
示例 1:
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5]
输出:9
提示
n == height.length1 <= n <= 2 * 10^40 <= height[i] <= 10^5
解题思路
方法一:单调栈
单调栈是一种利用栈结构来解决此类问题的方法。其核心思想是通过维护一个单调递减的栈,来找到每个柱子左右两侧的“边界”,从而计算出能接的雨水量。
算法步骤
- 初始化一个栈
st,用于存储柱子的索引。 - 遍历数组
height,对于每个柱子:- 如果当前柱子高度大于栈顶柱子的高度(即发现更高的右边界),则:
- 弹出栈顶元素(作为中间柱子)。
- 如果栈不为空,则计算当前柱子与栈顶柱子之间的雨水量:
- 高度差:
h = min(height[st.top()], height[i]) - height[mid] - 宽度:
w = i - st.top() - 1 - 雨水量:
sum += h * w
- 高度差:
- 如果当前柱子高度大于栈顶柱子的高度(即发现更高的右边界),则:
- 将当前柱子索引入栈。
- 遍历结束后,返回总雨水量。
C++代码实现
class Solution {
public:int trap(vector<int>& height) {if (height.size() <= 2) return 0; // 可以不加stack<int> st;int sum = 0;for (int i = 0; i < height.size(); i++) {while (!st.empty() && height[i] >= height[st.top()]) { // 发现有更高的右边界int mid = st.top(); // 单调栈第一个拿来当作盛水的低st.pop(); // 拿来用就给扔了,没用了if (!st.empty()) { // 看下单调栈是否为空,别是空的,保证左边能盛水int h = min(height[st.top()], height[i]) - height[mid]; // 这是找左边最大值int w = i - st.top() - 1; // 注意减一,只求中间宽度sum += h * w;}} // 注意while还在循环,因为右边多了一组墙,左边多了几组雨水st.push(i); // 把当前这个最大值扔进去,当作左边的墙}return sum;}
};
C语言代码实现
int trap(int* height, int heightSize) {int n = heightSize;if (n == 0) {return 0;}int ans = 0;int stk[n], top = 0;for (int i = 0; i < n; ++i) {while (top && height[i] > height[stk[top - 1]]) {int stk_top = stk[--top];if (!top) {break;}int left = stk[top - 1];int currWidth = i - left - 1;int currHeight = fmin(height[left], height[i]) - height[stk_top];ans += currWidth * currHeight;}stk[top++] = i;}return ans;
}
方法二:动态规划
动态规划的核心思想是通过维护两个数组 leftMax 和 rightMax,分别表示每个柱子左侧和右侧的最大高度。通过这两个数组,可以快速计算出每个柱子能接的雨水量。
算法步骤
- 初始化两个数组
leftMax和rightMax,分别表示每个柱子左侧和右侧的最大高度。 - 遍历数组
height,计算leftMax和rightMax:leftMax[i] = max(leftMax[i-1], height[i])rightMax[i] = max(rightMax[i+1], height[i])
- 遍历数组
height,计算每个柱子能接的雨水量:result += min(leftMax[i], rightMax[i]) - height[i]
代码实现
class Solution {
public:int trap(vector<int>& height) {int n = height.size();if (n == 0) return 0;vector<int> leftMax(n, 0);vector<int> rightMax(n, 0);leftMax[0] = height[0];for (int i = 1; i < n; i++) {leftMax[i] = max(leftMax[i - 1], height[i]);}rightMax[n - 1] = height[n - 1];for (int i = n - 2; i >= 0; i--) {rightMax[i] = max(rightMax[i + 1], height[i]);}int result = 0;for (int i = 0; i < n; i++) {result += min(leftMax[i], rightMax[i]) - height[i];}return result;}
};
方法三:双指针优化
动态规划的方法需要额外的 O(n) 空间来存储 leftMax 和 rightMax。通过使用双指针,可以将空间复杂度优化到 O(1)。
算法步骤
- 初始化两个指针
left和right,分别指向数组的两端。 - 初始化两个变量
leftMax和rightMax,分别表示左侧和右侧的最大高度。 - 当
left < right时:- 更新
leftMax和rightMax:leftMax = max(leftMax, height[left])rightMax = max(rightMax, height[right])
- 如果
height[left] < height[right],则:result += leftMax - height[left]left++
- 否则:
result += rightMax - height[right]right--
- 更新
- 返回总雨水量。
代码实现
class Solution {
public:int trap(vector<int>& height) {int result = 0;int l = 0, r = height.size() - 1;int lMax = 0, rMax = 0;while (l < r) {lMax = max(lMax, height[l]);rMax = max(rMax, height[r]);if (height[l] < height[r]) {result += lMax - height[l];++l;} else {result += rMax - height[r];--r;}}return result;}
};
C语言代码实现
int trap(int* height, int heightSize) {int result = 0; // 用于存储最终能接的雨水总量int l = 0, r = heightSize - 1; // 初始化左右指针,l指向数组起始位置,r指向数组末尾位置int lMax = 0, rMax = 0; // 初始化左右最大高度变量,用于记录左右指针遍历过程中的最大柱子高度// 当左指针小于右指针时,继续循环,直到两个指针相遇while (l < r) {// 更新左指针左侧的最大高度lMax = lMax > height[l] ? lMax : height[l]; // 如果当前左指针指向的柱子高度大于lMax,则更新lMax// 更新右指针右侧的最大高度rMax = rMax > height[r] ? rMax : height[r]; // 如果当前右指针指向的柱子高度大于rMax,则更新rMax// 根据左右指针指向的柱子高度,决定移动哪个指针if (height[l] < height[r]) {// 如果左指针指向的柱子高度小于右指针指向的柱子高度// 说明左指针处的柱子可以确定其能接的雨水量(由左最大值lMax决定)result += lMax - height[l]; // 计算当前左指针处能接的雨水量,并累加到result中++l; // 左指针向右移动一位} else {// 如果左指针指向的柱子高度大于等于右指针指向的柱子高度// 说明右指针处的柱子可以确定其能接的雨水量(由右最大值rMax决定)result += rMax - height[r]; // 计算当前右指针处能接的雨水量,并累加到result中--r; // 右指针向左移动一位}}// 当左右指针相遇时,遍历结束,返回能接的雨水总量return result;
}
总结
- 单调栈:时间复杂度
O(n),空间复杂度O(n)。适合对空间复杂度要求不高的场景。 - 动态规划:时间复杂度
O(n),空间复杂度O(n)。思路清晰,适合初学者理解。 - 双指针优化:时间复杂度
O(n),空间复杂度O(1)。最优解,适合对空间复杂度要求较高的场景。
接雨水这个经典题目,看似很难,但是实际上只是考察单调栈的使用。别的还是很容易的。
相关文章:
每日一题——接雨水
接雨水问题详解 视频学习推荐 建议先参考以下视频进行学习: 问题描述 给定一个非负整数数组 height,表示每个宽度为 1 的柱子的高度图。计算按此排列的柱子,下雨之后能接多少雨水。 示例 示例 1: 输入:height …...
MetaGPT发布的MGX与Devin深度对比
家人们,搞编程的都知道,工具选对了,效率能翻倍!今天必须给大伙唠唠MetaGPT发布的MGX编程助手和Devin编程助手 。 先看MGX,简直是编程界的王炸!它就像一个超神的虚拟开发团队,一堆智能助手分工明…...
网络安全技术整体架构 一个中心三重防护
网络安全技术整体架构:一个中心三重防护 在信息技术飞速发展的今天,网络安全的重要性日益凸显。为了保护信息系统不受各种安全威胁的侵害,网络安全技术整体架构应运而生。本文将详细介绍“一个中心三重防护”的概念,并结合代码示…...
03.06 QT
一、使用QSlider设计一个进度条,并让其通过线程自己动起来 程序代码: <1> Widget.h: #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QThread> #include "mythread.h"QT_BEGIN_NAMESPACE namespace Ui {…...
【YOLOv12改进trick】多尺度大核注意力机制MLKA模块引入YOLOv12,实现多尺度目标检测涨点,含创新点Python代码,方便发论文
🍋改进模块🍋:多尺度大核注意力机制(MLKA) 🍋解决问题🍋:MLKA模块结合多尺度、门控机制和空间注意力,显著增强卷积网络的模型表示能力。 🍋改进优势🍋:超分辨的MLKA模块对小目标和模糊目标涨点很明显 🍋适用场景🍋:小目标检测、模糊目标检测等 🍋思路…...
SpringUI:打造高质量Web交互设计的首选元件库
SpringUI作为一个专为Web设计与开发领域打造的高质量交互元件库,确实为设计师和开发者提供了极大的便利。以下是对SpringUI及其提供的各类元件的详细解读和一些建议: SpringUI概述 SpringUI集合了一系列预制的、高质量的交互组件,旨在帮助设…...
鸿蒙Android4个脚有脚线
效果 min:number122max:number150Row(){Stack(){// 底Text().border({width:2,color:$r(app.color.yellow)}).height(this.max).aspectRatio(1)// 长Text().backgroundColor($r(app.color.white)).height(this.max).width(this.min)// 宽Text().backgroundColor($r(app.color.w…...
夏门大学DeepSeek 手册:从社会大众到高校及企业的全面应用实践研究(附 PDF 下载)
这 3 份手册分别从 DeepSeek 大模型概念、技术与应用实践、DeepSeek 大模型赋能高校教学和科研、DeepSeek 大模型及其企业应用实践-企业人员的大模型宝典几个角度进行全面分析,可以结合着清华、北大系列相互对照着学习。 清华北大推出的 DeepSeek 教程(…...
嵌入式学习第二十三天--网络及TCP
进程通信的方式: 同一主机 传统 system V 不同主机 网络 --- 解决不同主机间 的进程间通信 网络 (通信) //1.物理层面 --- 联通(通路) //卫星 2G 3G 4G 5G 星链 (千帆) //2.逻辑层面 --- 通路(软件) MAC os LINUX …...
策略模式详解:实现灵活多样的支付方式
多支付方式的实现:策略模式详解 策略模式(Strategy Pattern)是一种行为设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互换使用。策略模式使得算法可以独立于使用它的客户端变化。本文将通…...
【Java篇】算术如诗,逻辑似梦:Java 编程中的运算符探寻
文章目录 Java 运算符:在计算与逻辑之中追寻编程的哲理1.前言2. 算术运算符2.1 基本四则运算符:加减乘除( - * / %)2.2 除法与取余2.3 增量运算符( --)2.4 自增/自减运算符 3. 关系运算符3.1 关系运算符 4.…...
Docker小游戏 | 使用Docker部署DOS游戏合集
Docker小游戏 | 使用Docker部署DOS游戏合集 前言项目介绍项目简介项目预览二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署dos-games网页小游戏下载镜像创建容器检查容器状态检查服务端口检查容器日志安全设置四、访问DOS游戏网页五、进阶玩法下载游戏拷贝…...
【大模型系列篇】国产开源大模型DeepSeek-V3技术报告解析
DeepSeek-V3技术报告 目录 DeepSeek-V3技术报告 1. 摘要 2. 引言 3. DeepSeek V3 架构 3.1 基础架构 3.1.1. 多头潜在注意力 3.1.2. DeepSeekMoE和无辅助损失的负载均衡 3.2 多令牌预测 4. 基础设施 4.1 计算集群 4.2 训练框架 4.2.1. DualPipe算法与计算通信协同优…...
双足机器狗开发:Rider - Pi
双足机器狗开发:Rider - Pi https://github.com/YahboomTechnology/Rider-Pi-Robot 项目介绍 Rider - Pi是一款为开发者、教育工作者和机器人爱好者设计的桌面双轮腿式机器人,它基于树莓派CM4核心模块构建,具备多种先进功能和特点: 硬件特性 核心模块:采用树莓派CM4核…...
以商业思维框架为帆,驭创业浪潮前行
创业者踏入商海,如同航海家奔赴未知海域,需有清晰的思维罗盘指引方向。图中“为什么—用什么—怎么做—何人做—投入产出”的商业框架,正是创业者破解商业谜题的密钥,从需求洞察到落地执行,为创业之路铺就逻辑基石。 …...
基于单片机的智慧音乐播放系统研究
标题:基于单片机的智慧音乐播放系统研究 内容:1.摘要 随着科技的飞速发展,人们对音乐播放系统的智能化和个性化需求日益增长。本研究的目的是设计并实现一个基于单片机的智慧音乐播放系统。采用单片机作为核心控制单元,结合音频解码模块、存储模块和人机…...
ApoorvCTF Rust语言逆向实战
上周参加了国外的比赛,名称叫:ApoorvCTF 看一下老外的比赛跟我们有什么不同,然后我根据国内比赛对比发现,他们考点还是很有意思的,反正都是逆向,哈哈哈 Rusty Vault 题目描述: In the h…...
Mysql回表查询、索引覆盖等概念
参考:【mysql】MySQL中的回表查询、索引覆盖、索引下推、谓词下推_mysql回表-CSDN博客 【一】回表查询 【1】索引的存储形式 在InnoDB存储引擎中,根据索引的存储形式,又可以分为以下两种: 分类含义特点聚集索引必须有࿰…...
Ubuntu20.04本地配置IsaacLab 4.2.0的G1训练环境(二):训练与推理
Ubuntu20.04本地配置IsaacLab4 4.2.0的G1训练环境(二):训练与推理 训练推理 写在前面,本文档的实现需要IsaacLab的成功安装,可参考(一)。 训练 在IsaacLab目录下,isaaclab的conda虚…...
《实战AI智能体》深度解析Deepseek可以做什么?
一、Deepseek平台功能全景图 Deepseek作为新一代人工智能开发平台,通过整合多项核心技术能力,构建了覆盖多领域的AI服务体系。该平台不仅为终端用户提供智能化解决方案,更为开发者群体打造了高效的技术支撑平台,形成了完整的AI应用开发生态。 二、核心功能模块解析 2.1 智…...
Android 仿 DeepSeek 思考效果:逐字显示 AI 生成内容,支持加粗、颜色,复制内容
最近特别火的非AI莫属了,对我们高级搬运工太友好了,不管是网页端还是APP端,输入你要问的问题,都会逐字给你显示出来,有的还会加粗,这种效果看着不错,今天就带大家一起来实现。有啥更好的建议请在…...
联合索引关于In和范围查询影响索引使用的情况分析
索引类型 1、unique ,唯一索引 2、normal,普通索引 3、fulltext, 全文索引 4、spatial,空间索引 样例 三个字段的联合索引,走一个字段是key_len是5,三个是15. 联合索引关于 使用in是不影响后续列 范围查询大于或小于…...
八点八数字科技:AI数字人引领智慧文旅新时代
在数字化浪潮席卷全球的今天,八点八数字科技凭借其领先的AI数字人技术,正在为文旅行业带来一场前所未有的变革。作为全球领先的IP智能体服务商,八点八数字科技通过自主研发的AI数字人全息舱、数字人一体机等创新产品,为智慧文旅注…...
python绘图之组合图表
组合图表(也称为多子图或多面板图表)是一种将多个图表组合在一起的可视化方式,主要用于同时展示多个相关的数据集或数据维度。本节我们学习使用python绘制组合图表 import matplotlib.pyplot as plt import numpy as np# 生成随机数据 x np.…...
pytest框架 核心知识的系统复习
1. pytest 介绍 是什么:Python 最流行的单元测试框架之一,支持复杂的功能测试和插件扩展。 优点: 语法简洁(用 assert 替代 self.assertEqual)。 自动发现测试用例。 丰富的插件生态(如失败重试、并发执…...
【人工智能】实现【DeepSeek】使用【Anything LLM】并使用本地知识库回答!本地部署告别服务器崩溃的烦恼!
本地知识库回答不准确(Anything LLM + Ollama ) 很多动手能力强的人根据网上的教程,部署了自己的本地知识库。但是发现知识库回答的不准确,甚至答非所问。 先看部署知识库的对比效果,本地大模型为deepseek1.5b 配置为 Anything LLM + Ollama,知识库内容为两篇手机公司文…...
RV1126+FFMPEG多路码流监控项目
一.项目介绍: 本项目采用的是易百纳RV1126开发板和CMOS摄像头,使用的推流框架是FFMPEG开源项目。这个项目的工作流程如下(如上图):通过采集摄像头的VI模块,再通过硬件编码VENC模块进行H264/H265的编码压缩,并把压缩后的…...
人工智能之数学基础:对线性代数中逆矩阵的思考?
本文重点 逆矩阵是线性代数中的一个重要概念,它在线性方程组、矩阵方程、动态系统、密码学、经济学和金融学以及计算机图形学等领域都有广泛的应用。通过了解逆矩阵的定义、性质、计算方法和应用,我们可以更好地理解和应用线性代数知识,解决各种实际问题。 关于逆矩阵的思…...
计算机网络(1) 网络通信基础,协议介绍,通信框架
网络结构模式 C/S-----客户端和服务器 B/S -----浏览器服务器 MAC地址 每一个网卡都拥有独一无二的48位串行号,也即MAC地址,也叫做物理地址、硬件地址或者是局域网地址 MAC地址表示为12个16进制数 如00-16-EA-AE-3C-40 (每一个数可以用四个…...
【音视频】ffplay常用命令
一、 ffplay常用命令 -x width:强制显示宽度-y height:强制显示高度 强制以 640*360的宽高显示 ffplay 2.mp4 -x 640 -y 360 效果如下 -fs 全屏显示 ffplay -fs 2.mp4效果如下: -an 禁用音频(不播放声音)-vn 禁…...
