LeetCode接雨水问题:双指针解法与优化策略
1. 问题背景与核心挑战接雨水是LeetCode题库中一道经典的Hard级别算法题编号42考察对数组处理、动态规划和双指针等核心编程思想的综合运用能力。题目描述如下给定n个非负整数表示的高度图每个柱子的宽度为1计算下雨后这些柱子能接住多少雨水。举个实际例子对于高度数组[0,1,0,2,1,0,1,3,2,1,2,1]对应的雨水存储情况如下图所示■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■其中■表示柱子空白部分表示存储的雨水。这个案例中总共能接6个单位的雨水。这道题之所以被归类为Hard难度主要因为需要将三维的雨水存储问题抽象为二维的高度计算多种解法之间存在显著的时间/空间复杂度差异边界条件的处理容易出错如最左/最右柱子最优解的双指针法需要巧妙的思路转换在实际面试中这道题出现在Amazon、Google、Microsoft等公司的技术面试中频率较高因为它能有效考察候选人的问题分析能力和算法思维。2. 暴力解法与初步优化2.1 直观的按列计算法最直观的解法是按列计算每个位置能存储的雨水量。对于数组中的每个元素height[i]它能存储的雨水量由其左右两侧最高柱子的较小值决定water[i] min(left_max, right_max) - height[i]如果这个值大于0则计入总水量。实现代码如下def trap_brute_force(height): total 0 n len(height) for i in range(1, n-1): left_max max(height[:i]) right_max max(height[i1:]) water min(left_max, right_max) - height[i] if water 0: total water return total注意这种方法的时间复杂度是O(n²)因为对每个元素都要扫描其左右两侧。在LeetCode上提交会因超时无法通过所有测试用例。2.2 预计算优化法我们可以通过预计算将左右最大值存储下来将时间复杂度优化到O(n)def trap_precompute(height): if not height: return 0 n len(height) left_max [0] * n right_max [0] * n left_max[0] height[0] for i in range(1, n): left_max[i] max(left_max[i-1], height[i]) right_max[-1] height[-1] for i in range(n-2, -1, -1): right_max[i] max(right_max[i1], height[i]) total 0 for i in range(n): water min(left_max[i], right_max[i]) - height[i] if water 0: total water return total这种方法虽然通过了时间限制但需要O(n)的额外空间存储左右最大值。在面试中面试官通常会进一步要求优化空间复杂度。3. 最优解双指针法3.1 算法思路双指针法能在O(n)时间复杂度和O(1)空间复杂度下解决问题。核心思想是使用左右两个指针从两端向中间移动维护左右两侧遇到的最大高度left_max和right_max每次移动较小max值的指针因为水量由较小值决定计算当前位置能存储的水量并累加def trap_two_pointers(height): if not height: return 0 left, right 0, len(height) - 1 left_max right_max 0 total 0 while left right: if height[left] height[right]: if height[left] left_max: left_max height[left] else: total left_max - height[left] left 1 else: if height[right] right_max: right_max height[right] else: total right_max - height[right] right - 1 return total3.2 为什么这种方法有效关键在于理解为什么可以移动较小max值的指针。假设height[left] height[right]此时left_max right_max一定成立因为right_max记录的是右侧历史最大值所以当前left位置的水量由left_max决定min(left_max, right_max) left_max即使右侧有更高的柱子也不会影响当前left位置的水量计算这种方法的精妙之处在于它动态地跟踪了可能影响水量的关键因素避免了不必要的计算。4. 边界条件与常见错误4.1 必须处理的特殊情况空数组或长度小于3的数组无法形成凹槽存储水单调递增/递减的数组无法存储水所有柱子高度相同无法存储水4.2 常见实现错误未正确处理边界柱子第一个和最后一个柱子不能储水在双指针法中错误地移动指针应该总是移动较小max值的指针忘记检查计算出的水量是否为正数在预计算方法中数组初始化错误应该初始化为当前高度提示在面试中建议先讨论这些边界情况展示你的全面思考能力。5. 算法扩展与变种5.1 3D接雨水问题LeetCode第407题Trapping Rain Water II将问题扩展到三维。这种情况下需要使用最小堆优先队列来跟踪边界高度时间复杂度为O(mn log(mn))。5.2 柱状图中最大矩形与此题相关的另一道经典题目是LeetCode 84柱状图中最大的矩形可以使用单调栈在O(n)时间内解决。5.3 实际工程应用这种算法思想可以应用于地理信息系统中的地形分析建筑设计中排水系统计算图像处理中的区域分割资源分配中的瓶颈分析6. 面试技巧与解题策略6.1 解题步骤建议先理解题意并举例说明画图很重要提出暴力解法并分析复杂度思考优化方向时间/空间逐步推导最优解可以从小规模例子开始讨论边界条件和特殊情况编写代码并测试6.2 面试官可能追问的问题如何证明你的算法是正确的如果柱子宽度不固定如[宽度高度]数组如何修改算法如何并行化这个算法以处理大规模数据如果要求实时计算滑动窗口内的储水量如何设计6.3 代码实现细节在实现双指针法时注意循环条件是left right不是先更新max值再计算水量移动指针时注意不要越界可以添加early termination条件如剩余柱子都低于当前max7. 性能对比与测试用例7.1 各解法性能对比方法时间复杂度空间复杂度LeetCode运行时间暴力法O(n²)O(1)超时预计算法O(n)O(n)60ms双指针法O(n)O(1)48ms单调栈法未讨论O(n)O(n)64ms7.2 推荐测试用例test_cases [ ([0,1,0,2,1,0,1,3,2,1,2,1], 6), # 标准案例 ([], 0), # 空数组 ([1], 0), # 单元素 ([1,2,3,4], 0), # 单调递增 ([4,3,2,1], 0), # 单调递减 ([3,1,2,1,3], 5), # 对称案例 ([5,4,3,2,1,2,3,4,5], 16), # V型案例 ([1,0,1,0,1], 2) # 交替案例 ]8. 不同语言的实现要点8.1 C实现注意事项int trap(vectorint height) { int left 0, right height.size() - 1; int left_max 0, right_max 0; int ans 0; while (left right) { if (height[left] height[right]) { height[left] left_max ? (left_max height[left]) : ans left_max - height[left]; left; } else { height[right] right_max ? (right_max height[right]) : ans right_max - height[right]; --right; } } return ans; }注意C中三元运算符的使用可以使代码更简洁但可读性会降低。8.2 Java实现要点public int trap(int[] height) { int left 0, right height.length - 1; int leftMax 0, rightMax 0; int res 0; while (left right) { if (height[left] height[right]) { if (height[left] leftMax) { leftMax height[left]; } else { res leftMax - height[left]; } left; } else { if (height[right] rightMax) { rightMax height[right]; } else { res rightMax - height[right]; } right--; } } return res; }Java实现中要注意数组越界检查建议先检查height.length是否为0。8.3 JavaScript实现技巧function trap(height) { let left 0, right height.length - 1; let leftMax 0, rightMax 0; let result 0; while (left right) { if (height[left] height[right]) { height[left] leftMax ? leftMax height[left] : result leftMax - height[left]; left; } else { height[right] rightMax ? rightMax height[right] : result rightMax - height[right]; right--; } } return result; }JS中可以使用箭头函数和更简洁的三元运算符但要注意浏览器兼容性。9. 实际工程中的优化考虑9.1 大数据量处理当柱子数量极大如处理地理数据时可以考虑分块处理将数据分成多个块分别计算后合并结果并行计算使用多线程或分布式计算处理不同区段流式处理对于实时数据流维护滑动窗口的最大值9.2 内存优化对于内存受限的环境使用双指针法避免存储额外数组如果必须存储预处理结果可以考虑使用更紧凑的数据结构对于极大数组可以只存储关键转折点而非全部数据9.3 数值精度问题当处理浮点数高度时注意比较时的精度误差使用epsilon比较累计水量时可能需要注意大数相加的问题考虑使用更高精度的数值类型如double而非float10. 学习资源与进阶题目10.1 推荐学习资料《算法导论》中的动态规划章节LeetCode的Two Pointers专题GeeksforGeeks上的雨水收集问题详解麻省理工开放课程《算法设计与分析》10.2 相关进阶题目LeetCode 11: 盛最多水的容器LeetCode 84: 柱状图中最大的矩形LeetCode 407: 接雨水 II3D版本LeetCode 755: 倒水问题10.3 可视化工具推荐LeetCode官方的问题可视化VisuAlgo算法可视化平台Python的matplotlib库绘制高度图使用Jupyter Notebook交互式调试掌握接雨水这类问题的解法不仅能帮助你在技术面试中表现出色更重要的是培养了将现实问题抽象为计算模型的能力。在实际工程中这种能力比记住特定算法更有价值。建议在理解基础解法后尝试自己推导出优化方案这样印象会更加深刻。

相关新闻

Supabase:开源BaaS平台,PostgreSQL驱动的全栈开发利器

Supabase:开源BaaS平台,PostgreSQL驱动的全栈开发利器

1. 项目概述:Supabase到底是什么?最近在Vibe Coding的社群里,Supabase这个名字被反复提及,频率高到让我这个老码农都忍不住侧目。很多刚入行的朋友,甚至一些有经验但主要用传统单体架构的开发者,都在问同一…

2026/11/3 0:42:20 阅读更多 →
滑模控制在车辆稳定性系统中的应用与优化

滑模控制在车辆稳定性系统中的应用与优化

1. 高速行驶中的车辆稳定性挑战当车速超过120km/h时,车辆动力学特性会发生显著变化。前轮转向角度的微小变化可能导致车身姿态的剧烈波动,这种非线性特性在紧急变道或强侧风条件下尤为明显。去年我在测试某款电动SUV时,就曾亲历过80km/h横风下…

2026/11/2 21:46:22 阅读更多 →
排队论实战:从Gen Con 2026现场74000名观众看大型活动容量规划

排队论实战:从Gen Con 2026现场74000名观众看大型活动容量规划

# 排队论实战:从Gen Con 2026现场74000名观众看大型活动容量规划8 月 6 日,世界最大桌游展会 Gen Con 2026 交出一份惊人的成绩单:超过 74000 名观众涌入美国印第安纳波利斯,连续第三届全部门票售罄,四天展期为当地带来…

2026/11/3 1:34:14 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/3 1:09:25 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/2 10:46:11 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/2 10:47:40 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/2 1:16:51 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/2 10:46:31 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/2 10:46:26 阅读更多 →

日新闻

周新闻

月新闻