当前位置: 首页 > news >正文

力扣(接雨水)——基于最高柱分割的双指针

深度解析 LeetCode 42. 接雨水:基于最高柱分割的双指针解法

一、题目剖析

在这里插入图片描述

给定表示柱子高度的数组 height,需计算下雨后能承接的雨水总量。雨水留存的关键在于凹槽结构—— 左右两侧存在更高的柱子,中间柱子较低,形成储水空间。核心挑战是高效定位所有凹槽,计算其储水量。

二、算法思路:最高柱分割 + 双指针遍历

(一)核心思想

  1. 最高柱定位:先找到数组中最高柱子的下标(rightMax 初始职责 ),以此为界,将数组分为左侧区域(最高柱左侧 )和右侧区域(最高柱右侧 )。
  2. 分区域处理
    • 左侧区域:从左向右遍历,维护 leftMax(遍历过的最高柱下标 )。若当前柱子低于 leftMax,则可储水(储水量为 leftMax 与当前柱的高度差 );若当前柱子更高,则更新 leftMax
    • 右侧区域:从右向左遍历,维护 rightMax(遍历过的最高柱下标 )。若当前柱子低于 rightMax,则可储水(储水量为 rightMax 与当前柱的高度差 );若当前柱子更高,则更新 rightMax
  3. 双指针的隐含作用:通过分割后的单向遍历,每个区域的指针(如左侧的 curr )承担“动态扫描 + 储水判断”的双职责,本质是简化的双指针逻辑。

(二)逻辑推导

最高柱是天然的“边界屏障”—— 左侧区域的储水仅受左侧更高柱限制(右侧有最高柱兜底 ),右侧区域同理。利用这一特性,可将复杂的双向边界判断,简化为两个单向遍历,降低逻辑复杂度。

三、代码实现与逐行解析

//双指针:得到当前元素的左侧的最大值当前元素的右侧最大值,Math.min(leftMax,rightMax)再减去当前元素的柱子高度,得到可以存的积水
//忽略头和尾因为一个左侧没有柱子一个右侧没有柱子,没有办法存水
class Solution {public int trap(int[] height) {if (height == null || height.length < 3) {return 0;}int leftMax = 0;int rightMax = 0;int sumRain = 0;//得到当前最高的柱子作为rightMax;for (int len = 0; len < height.length; len++) {if (height[len] > height[rightMax]) {rightMax = len;}}//遍历最高柱子的左侧柱子if (rightMax > 0) {for (int curr = 1; curr < rightMax; curr++) {//判断leftMax是否比当前柱子大,如果小就存不了水,替换leftMaxcontinueif (height[curr] >= height[leftMax]) {leftMax = curr;}//小于则可以存水,存水的大小是leftMax-currelse {sumRain += height[leftMax] - height[curr];}}}//遍历最高柱子的右侧柱子//由于是后序遍历此时左侧柱子的最大值为原先的rightMaxleftMax = rightMax;if (leftMax < height.length - 1) {rightMax = height.length - 1;for (int curr = height.length - 2; curr > leftMax; curr--) {if (height[rightMax] <= height[curr]) {rightMax = curr;} else {sumRain += height[rightMax] - height[curr];}}}return sumRain;}
}

(一)代码流程拆解

  1. 边界处理:若数组为空或长度小于 3,直接返回 0(无法形成凹槽储水 )。
  2. 寻找全局最高柱:遍历数组,找到最高柱子的下标 rightMax,作为左右区域的分割点。
  3. 处理左侧区域
    • 若最高柱不在数组开头(rightMax > 0 ),从第二个柱子(下标 1 )遍历到最高柱下标前一位(curr < rightMax )。
    • 维护 leftMax(左侧遍历过的最高柱下标 ),当前柱低于 leftMax 时,计算储水量并累加;否则更新 leftMax
  4. 处理右侧区域
    • 重置 leftMax 为全局最高柱下标,若最高柱不在数组结尾(leftMax < height.length - 1 ),从倒数第二个柱子(下标 length-2 )遍历到最高柱下标后一位(curr > leftMax )。
    • 维护 rightMax(右侧遍历过的最高柱下标 ),当前柱低于 rightMax 时,计算储水量并累加;否则更新 rightMax
  5. 返回结果:累加的储水量 sumRain 即为答案。

(二)关键逻辑解析

  • 最高柱的分割作用:将数组分为左右两个独立区域,每个区域的储水仅受单侧最高柱限制(左侧区域右侧有全局最高柱兜底,右侧区域左侧有全局最高柱兜底 ),简化了边界判断。
  • 单向遍历的高效性:左侧从左到右、右侧从右到左的遍历,避免了传统双指针的复杂条件判断,每个柱子仅遍历一次,时间复杂度为 O(n)
  • 储水量计算:利用“当前柱高度与遍历过的最高柱高度差”计算储水量,直接且高效,无需额外存储左右边界高度数组。

四、复杂度分析

(一)时间复杂度

  • 寻找全局最高柱:O(n)(遍历数组一次 )。
  • 处理左侧区域:O(n)(最多遍历最高柱左侧所有柱子 )。
  • 处理右侧区域:O(n)(最多遍历最高柱右侧所有柱子 )。
    总时间复杂度:O(n)n 为数组长度 ),线性时间复杂度保证了高效性。

(二)空间复杂度

仅使用常数级额外变量(leftMaxrightMaxsumRaincurr ),空间复杂度:O(1)

http://www.dtcms.com/a/335324.html

相关文章:

  • LLaVA
  • 胶质母细胞瘤对化疗的敏感性由磷脂酰肌醇3-激酶β选择性调控
  • MySQL 的 DDL / DML / DQL / DCL 做一次系统梳理:概念区别→常用语法→特点与注意点→实战小例子→常见面试/坑点速记
  • 解构下一-代 AI 智能体:超越 LLM,深度解析三大核心支柱——上下文、认知与行动
  • 基础数据结构
  • Linux——进程管理和计划任务管理
  • Python中*args和**kwargs
  • 基于springboot的在线视频教育管理系统设计与实现(源码+文档+部署讲解)
  • Flow-GRPO:通过在线 RL 训练 Flow matching 模型
  • 概率论基础教程第3章条件概率与独立性(二)
  • 如何解决C盘存储空间被占的问题,请看本文
  • C语言零基础第18讲:自定义类型—结构体
  • 9.从零开始写LINUX内核——设置中断描述符表
  • duiLib 实现鼠标拖动标题栏时,窗口跟着拖动
  • 深入了解 swap:作用、局限与分区建立
  • Linux sar命令详细使用指南
  • Effective C++ 条款45:运用成员函数模板接受所有兼容类型
  • Day2--滑动窗口与双指针--2090. 半径为 k 的子数组平均值,2379. 得到 K 个黑块的最少涂色次数,2841. 几乎唯一子数组的最大和
  • Linux软件编程:线程间通信
  • 【FreeRTOS】队列集
  • MySQL 插入数据提示字段超出范围?一招解决 DECIMAL 类型踩坑
  • 第三十七天(js前端数据加密和混淆)
  • Fixture Caliper 工具
  • GRPO(Group Relative Policy Optimization)公式速览
  • Scala面试题及详细答案100道(11-20)-- 函数式编程基础
  • 嵌入式软件架构设计之九: 双机通信之通信方式
  • 排列与组合
  • 超详细yolov8/11-obb旋转框全流程概述:配置环境、数据标注、训练、验证/预测、onnx部署(c++/python)详解
  • STM32标准库学习笔记
  • MM-Spatial和Spatial-MLLM论文解读