尧图网络科技 Logo 尧图网络科技
  • 首页
  • 关于我们
  • 建站服务
  • UI 设计
  • 案例展示
  • SEO 优化
  • 资讯中心
  • 联系我们

资讯详情

深度解读 · 专业分析

  • 首页
  • 资讯中心
  • /
  • 接雨水算法全解析:从错误到3种最优解法(含扩展与思路Trigger)

最新资讯

  • 全部资讯
  • 行业动态
  • UI 设计
  • SEO 优化
  • 网站开发

接雨水算法全解析:从错误到3种最优解法(含扩展与思路Trigger)

📅 发布时间:2026/6/20 8:38:48 👁 浏览次数:
接雨水算法全解析:从错误到3种最优解法(含扩展与思路Trigger)

接雨水算法全解析:从错误到3种最优解法(含扩展与思路Trigger)

接雨水问题是数组类算法的经典“拦路虎”——既考察对“凹陷容量计算”的本质理解,又要求灵活运用单调栈、双指针等数据结构/技巧。本文将从最常见的错误入手,拆解3种正确解法(覆盖不同场景需求),延伸同类型问题的通用思路,帮你彻底吃透这类“边界约束容量”的问题。

一、题目背景:接雨水的核心需求与难点

题目描述

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

核心示例

  • 输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
  • 输出:14(经典测试用例,直观展示“凹陷储水”的核心)

本质与难点

  • 储水本质:每个位置能接的水量 = 左右两侧最大高度的最小值 - 当前柱子高度(结果为正才有效);
  • 核心难点:如何高效找到每个位置的“左右最大高度”?如何避免冗余计算(时间/空间)?

与普通数组问题的区别

普通数组问题只需“单向遍历”,而接雨水需要“双向约束”(左右最大高度),因此需解决“如何同时兼顾两侧边界”的问题。

二、错误反思:用if代替while,漏掉的“连续凹陷”

最常见错误思路(单调栈版)

很多初学者会用单调栈思路,但因误用 if 代替 while,导致只处理了“单次凹陷”,漏掉了连续的多个凹陷(多个 mid_idx):

# 错误代码(核心问题:if只弹一次栈)
def trap(height):if not height:return 0stack = []count = 0for i in range(len(height)):# 错误:if只能弹出1次,连续凹陷会漏算if stack and height[i] > height[stack[-1]]:mid = stack.pop()if not stack:breakleft = stack[-1]h = min(height[left], height[i]) - height[mid]w = i - left - 1count += h * wstack.append(i)return count

错误本质:漏掉“连续多个mid_idx”

当遇到比栈顶高的元素时,可能存在多个连续的凹陷需要计算(而非仅一个)。例如 height = [0,1,0,2,1,0,1,3],遍历到 i=7(高度3)时,栈内有 [3,4,5,6](对应高度2、1、0、1):

  • 3 > 1(栈顶6)→ 弹出6(mid1),计算水量;
  • 3 > 0(栈顶5)→ 需继续弹出5(mid2),计算水量;
  • 3 > 1(栈顶4)→ 需继续弹出4(mid3),计算水量;
  • 3 > 2(栈顶3)→ 需继续弹出3(mid4),计算水量;

if 只能处理 mid1,剩下的 mid2-mid4 全部漏算,导致总水量少算。

反思总结

单调栈思路的核心是“连续弹出所有比当前元素矮的栈顶”,必须用 while 循环实现“持续弹出”,而非 if 的“单次弹出”——这是单调栈处理“连续凹陷”的关键。

三、3种正确解法:覆盖不同场景需求

解法一:单调栈(自底向上,批量处理凹陷)

核心逻辑

  • 栈特性:单调递减栈(存储柱子索引,栈顶为当前最矮的凹陷底部);
  • 核心操作:遍历到比栈顶高的元素时,while 持续弹出栈顶(作为 mid_idx),新栈顶为 left_idx,当前元素为 right_idx,计算 (min(left_h, right_h) - mid_h) * (right_idx - left_idx - 1) 的水量;
  • 本质:从“凹陷底部”向上计算,批量处理连续的凹陷。

正确代码(修正if→while)

def trap(height):if not height:return 0stack = []  # 存储索引,维持单调递减count = 0n = len(height)for i in range(n):# 关键:while持续弹出所有比当前元素矮的栈顶while stack and height[i] > height[stack[-1]]:mid_idx = stack.pop()if not stack:  # 无左边界,无法储水breakleft_idx = stack[-1]right_idx = i# 计算高度:左右边界最小值 - 凹陷底部高度h = min(height[left_idx], height[right_idx]) - height[mid_idx]# 计算宽度:左右边界间距 - 1w = right_idx - left_idx - 1count += h * wstack.append(i)return count

优缺点与适用场景

  • 优点:一次遍历完成,代码紧凑,能批量处理连续凹陷;
  • 缺点:需理解单调栈的弹出逻辑,思维门槛中等;
  • 适用场景:熟悉单调栈操作,想在一次遍历中解决问题。

解法二:预处理左右最大高度(自左向右,直观易懂)

核心逻辑

  • 分步计算:先通过两次线性遍历,分别得到每个位置的“左侧最大高度”和“右侧最大高度”,再第三次遍历计算每个位置的水量;
  • 本质:直接套用“储水公式”,将“找左右最大高度”和“计算水量”分离,逻辑直观。

正确代码

def trap(height):if not height or len(height) < 2:return 0n = len(height)left_max = [0] * n  # left_max[i]:0~i的最大高度right_max = [0] * n  # right_max[i]:i~n-1的最大高度total = 0# 自左向右计算left_maxleft_max[0] = height[0]for i in range(1, n):left_max[i] = max(left_max[i-1], height[i])# 自右向左计算right_maxright_max[-1] = height[-1]for i in range(n-2, -1, -1):right_max[i] = max(right_max[i+1], height[i])# 逐位置计算水量for i in range(n):water = min(left_max[i], right_max[i]) - height[i]total += max(0, water)  # 负数取0(无法储水)return total

优缺点与适用场景

  • 优点:逻辑最直观,无复杂数据结构,初学者入门首选;
  • 缺点:需额外两个数组(空间O(n)),三次线性遍历;
  • 适用场景:初学者、面试中追求“快速写对”,不纠结空间优化。

解法三:双指针贪心(O(1)空间,最优解)

核心逻辑

  • 贪心思想:矮侧决定水位(若 left_max ≤ right_max,则左侧位置的水位上限由 left_max 决定,无需关注右侧更远的高度);
  • 双指针操作:left 从左向右,right 从右向左,动态维护 left_max 和 right_max,直接在“能确定水位”的一侧计算水量;
  • 本质:对“预处理左右最大高度”的空间优化,用变量代替数组,空间从O(n)降至O(1)。

正确代码(优化后简洁版)

def trap(height):if len(height) < 2:return 0output = 0left, right = 0, len(height)-1left_max, right_max = height[left], height[right]while left < right:if left_max <= right_max:left += 1# 左侧水位由left_max决定,直接计算if height[left] < left_max:output += left_max - height[left]else:left_max = height[left]  # 更新左侧最大高度else:right -= 1# 右侧水位由right_max决定,直接计算if height[right] < right_max:output += right_max - height[right]else:right_max = height[right]  # 更新右侧最大高度return output

优缺点与适用场景

  • 优点:时间O(n)、空间O(1)(最优复杂度),逻辑紧凑,面试加分;
  • 缺点:需理解“矮侧决定水位”的贪心逻辑,思维门槛稍高;
  • 适用场景:面试中追求空间优化,展示算法深度。

三种解法核心对比

解法 时间复杂度 空间复杂度 核心特点 适用人群
单调栈(自底向上) O(n) O(n) 批量处理连续凹陷,一次遍历 熟悉单调栈的开发者
预处理左右最大高度 O(n) O(n) 逻辑最直观,分步计算 初学者、追求快速写对
双指针贪心(最优) O(n) O(1) 空间最优,贪心思想 面试进阶、追求极致优化

四、同类型扩展:“边界约束容量”问题通用思路

接雨水的核心是“找两侧边界的约束,计算中间凹陷容量”,这套思路可复用在多个经典问题中:

扩展1:盛最多水(LeetCode 11)

问题描述

给定n个非负整数,每个数代表坐标中的一个点 (i, ai),画n条垂直线,找出其中两条线,使得它们与x轴共同构成的容器可以容纳最多的水。

核心关联

  • 与接雨水的异同:同样是“双指针+边界约束”,但盛最多水是“找最大宽×最小高”,接雨水是“逐位置算凹陷容量”;
  • 解法:直接复用双指针思路,left 和 right 向中间收缩,优先移动矮侧(因为矮侧是容量瓶颈)。

代码片段

def maxArea(height):left, right = 0, len(height)-1max_water = 0while left < right:width = right - leftmin_h = min(height[left], height[right])max_water = max(max_water, width * min_h)# 移动矮侧,寻找更大的高度if height[left] < height[right]:left += 1else:right -= 1return max_water

扩展2:接雨水II(LeetCode 407)

问题描述

给定一个 m x n 的矩阵,其中每个单元格是一个非负整数表示的高度,计算这个矩阵能接多少雨水。

核心关联

  • 与接雨水的异同:从“一维数组”扩展到“二维矩阵”,核心仍为“找边界约束的最小高度”;
  • 解法:用优先队列(小顶堆)维护边界,从“最低边界”向内部扩散,计算每个单元格的储水量(类似二维版双指针贪心)。

扩展3:直方图最大矩形面积(LeetCode 84)

问题描述

给定非负整数数组 heights,每个元素表示直方图的柱子高度,宽度为1,找出直方图中最大的矩形面积。

核心关联

  • 与接雨水的异同:同样用单调栈,接雨水是“单调递减栈找左右更大元素”,该问题是“单调递增栈找左右更小元素”(矩形的左右边界);
  • 本质:单调栈的“反向应用”,都是通过栈快速找到每个元素的“边界约束”。

五、思路Trigger:再次遇到这类问题怎么想?

看到以下场景,直接触发对应思路:

  1. 一维数组+凹陷储水→ 优先选双指针贪心(O(1)空间)或预处理(直观);
  2. 一维数组+连续凹陷/批量处理→ 选单调栈(一次遍历);
  3. 二维矩阵+储水→ 优先小顶堆(维护边界,扩散计算);
  4. 找最大容量/面积(非凹陷)→ 双指针(移动矮侧,优化瓶颈);
  5. 找每个元素的左右边界(更大/更小)→ 单调栈(一次遍历找所有边界)。

六、一句话记忆

接雨水三解法,栈预处理双指针;栈批处理,预处理直观,双指针最优;边界约束是核心,单调栈双指针通杀同类题。

七、总结

接雨水问题的3种解法,分别对应不同的思维层次:预处理是“直观入门”,单调栈是“数据结构应用”,双指针是“贪心优化”。最常见的错误是用 if 代替 while 漏掉连续凹陷,修正后就能掌握单调栈解法。

更重要的是,这类“边界约束容量/面积”的问题,核心思路都是“找到每个位置的左右约束,再计算目标值”——单调栈和双指针是解决这类问题的“万能工具”,掌握后可举一反三,轻松应对盛最多水、直方图最大矩形等同类题。

面试中,可根据自身熟悉程度选择解法:初学者先写预处理,熟练后用双指针展示优化能力,若面试官追问“能否用单调栈实现”,再补充栈解法,全方位展示你的算法功底~

相关新闻

C#性能优化基础:高CPU使用率(trace)

C#性能优化基础:高CPU使用率(trace)

2026/6/20 8:35:10 查看详情
详细介绍:Linux Bash(一)

详细介绍:Linux Bash(一)

2026/6/18 15:53:44 查看详情
pytest测试range内置函数

pytest测试range内置函数

2026/6/18 23:08:28 查看详情
DeepSeek-V4本地部署实战指南:CUDA/昇腾/ROCm三路径避坑全解析

DeepSeek-V4本地部署实战指南:CUDA/昇腾/ROCm三路径避坑全解析

2026/6/20 8:35:30 查看详情
如何突破GitHub访问限制:国内开发者必备的加速解决方案

如何突破GitHub访问限制:国内开发者必备的加速解决方案

2026/6/20 8:35:30 查看详情
WebAssembly 前沿技术与跨语言互操作:从 WASI 到 Component Model 的演进之路

WebAssembly 前沿技术与跨语言互操作:从 WASI 到 Component Model 的演进之路

2026/6/20 8:35:30 查看详情
Horos深度技术解析:如何基于开源架构构建专业级医学影像工作站

Horos深度技术解析:如何基于开源架构构建专业级医学影像工作站

2026/6/20 8:33:19 查看详情
【Vivado ROM IP核】从配置到验证:手把手构建你的第一个片上只读存储器

【Vivado ROM IP核】从配置到验证:手把手构建你的第一个片上只读存储器

2026/6/20 8:33:19 查看详情
滤袋厂家推荐排行榜:各维度实测避坑指南 - 速递信息

滤袋厂家推荐排行榜:各维度实测避坑指南 - 速递信息

2026/6/20 8:33:19 查看详情
团队博客 5:Sprint 3——收官与优化

团队博客 5:Sprint 3——收官与优化

2026/6/20 0:00:19 查看详情
3分钟掌握微信语音转换:Silk v3解码器完整使用指南

3分钟掌握微信语音转换:Silk v3解码器完整使用指南

2026/6/20 0:01:25 查看详情
VAC进程监控模块完全解析:3种扫描类型与虚拟方法表技术揭秘

VAC进程监控模块完全解析:3种扫描类型与虚拟方法表技术揭秘

2026/6/20 0:01:25 查看详情
从Landsat到高分系列:手把手教你选择适合自己项目的遥感卫星数据

从Landsat到高分系列:手把手教你选择适合自己项目的遥感卫星数据

2026/6/20 3:05:19 查看详情
福州空调维修上门加氟移机空调不制冷、推荐本地老牌鑫盛达、冷顺安 - 我叫一

福州空调维修上门加氟移机空调不制冷、推荐本地老牌鑫盛达、冷顺安 - 我叫一

2026/6/20 4:00:16 查看详情
嵌入式调试器组件化界面与拖拽交互技术详解

嵌入式调试器组件化界面与拖拽交互技术详解

2026/6/20 2:29:50 查看详情
YOLOv11涨点改进| CVPR 2026 | 独家创新首发、特征融合改进篇| 引入CMGF 引导特征融合机制,实现对不同模态特征的自适应增强与高效融合,助力多模态目标检测,小目标检测或分割有效涨点

YOLOv11涨点改进| CVPR 2026 | 独家创新首发、特征融合改进篇| 引入CMGF 引导特征融合机制,实现对不同模态特征的自适应增强与高效融合,助力多模态目标检测,小目标检测或分割有效涨点

2026/6/19 22:53:17 查看详情
E-E-A-T 成第一权重:2027 年无经验内容将被彻底淘汰

E-E-A-T 成第一权重:2027 年无经验内容将被彻底淘汰

2026/6/20 4:40:29 查看详情
深圳福田园岭老小区搬家公司推荐 经验足师傅高效搬运攻略 - 从来都是英雄出少年

深圳福田园岭老小区搬家公司推荐 经验足师傅高效搬运攻略 - 从来都是英雄出少年

2026/6/18 22:29:04 查看详情

关于尧图

立足北京本地的一站式网站建设服务与设计教学平台,深耕企业网站定制开发、全网 SEO 优化及网络推广服务。

快速链接

  • 关于我们
  • 建站服务
  • 案例展示
  • 资讯中心

服务项目

  • 企业官网定制
  • UI 界面设计
  • SEO 优化推广
  • 移动端适配

联系方式

电话:400-XXX-XXXX

邮箱:info@zskr.cn

地址:北京市朝阳区 XXX 路 XX 号

© 2026 尧图网络科技 版权所有 | 京 ICP 备 XXXXXXXX 号