hot100 接雨水(42)

📅 2026/6/27 4:26:37
hot100 接雨水(42)
本分析针对“接雨水”问题的双指针优化解法进行全方位推导与结构化拆解。该解法利用双向相向指针将传统动态规划的空间复杂度从 $O(n)$ 降低至 $O(1)$时间复杂度稳定在 $O(n)$。该解法通过局部最值的相对大小直接锁定全局边界瓶颈是处理此类线性空间截留问题的最优资源配置方案。一、 问题本质与数学模型对于长度为 n 的非负整数数组 height设任意位置 i其中 0 i n的蓄水量为 V[i]。位置 i 的蓄水量由其左侧所有柱子的最大高度 L[i] 和右侧所有柱子的最大高度 R[i] 共同决定。其物理本质遵循“木桶短板效应”即由较矮的一侧边界决定水面高度。其数学定义如下L[i] max(height[0 ... i])R[i] max(height[i ... n-1])V[i] min(L[i], R[i]) - height[i]整个高度图的总蓄水量Total_V即为所有位置蓄水量的线性累加 Total_V 累加所有位置的 (min(L[i], R[i]) - height[i])二、 算法演进对比在各类解法中双指针法在时空资源利用率上达到了平衡的最优状态解法名称时间复杂度空间复杂度核心原理物理瓶颈按列暴力枚举O(n^2)O(1)每次向左右两侧线性扫描最值重复扫描相同区间效率低下动态规划 (DP)O(n)O(n)预先通过两次遍历存储所有 L[i] 和 R[i]需要额外的数组空间开销单调栈O(n)O(n)维护一个单调递减栈按行计算水砖面积栈内元素在最坏情况下达到 n 个双指针法O(n)O(1)相向移动双指针动态维护局部最值无为时空复杂度理论极限三、 双指针核心逻辑的推导双指针法的核心在于不需要完全确定 L[i] 和 R[i] 的具体数值只需确定两者的相对大小关系。1. 变量初始化left 0, right n - 1pre记录 height[0 ... left] 的最大值。suf记录 height[right ... n-1] 的最大值。2. 逻辑断言一当 pre suf 时left 位置的瓶颈必为 pre推导 已知 suf 是右侧已遍历区域 height[right ... n-1] 的最大值。因为 right 指针在 left 指针的右侧所以 left 位置右侧的绝对最大高度 R[left] 必然大于或等于当前已知的右侧最大值 suf即 R[left] suf。 又因为当前触发条件为 pre suf结合不等式传递性可得pre suf R[left]即 pre R[left]。 因此根据蓄水公式left 位置的实际水面高度由较矮的 pre 决定min(L[left], R[left]) pre。结论此时 left 位置的蓄水量完全确定为pre - height[left]。处理后 left 指针右移。3. 逻辑断言二当 pre suf 时right 位置的瓶颈必为 suf推导 同理right 位置左侧的绝对最大高度 L[right] 必然大于或等于当前左侧最大值 pre即 L[right] pre。 已知 pre suf代入可得L[right] pre suf即 L[right] suf。 因此right 位置的实际水面高度由较矮的 suf 决定min(L[right], R[right]) suf。结论此时 right 位置的蓄水量完全确定为suf - height[right]。处理后 right 指针左移。四、 算法执行状态机步进示例以输入数据height [4, 2, 0, 3]为例算法内部状态变量的演进过程如下表所示步骤指针状态pre 值suf 值条件判断蓄水量增量 (ans)指针移动方向初始化left0, right300-ans 0-第 1 步left0, right3max(0,4) 4max(0,3) 3pre suf (4 3) 为 Falseans 3 - 3 0right 减 1 (变为 2)第 2 步left0, right2max(4,4) 4max(3,0) 3pre suf (4 3) 为 Falseans 3 - 0 3right 减 1 (变为 1)第 3 步left0, right1max(4,4) 4max(3,2) 3pre suf (4 3) 为 Falseans 3 - 2 1right 减 1 (变为 0)结束left0, right0--left right 为 False最终 ans 4循环终止五、 Java 源码实现标准纯净版Javaclass Solution { public int trap(int[] height) { // 边界条件判定若数组长度小于3无法形成凹槽蓄水量必然为0 if (height null || height.length 3) { return 0; } int left 0; int right height.length - 1; int ans 0; // pre 动态维护从左端到当前 left 的最大高度 int pre 0; // suf 动态维护从右端到当前 right 的最大高度 int suf 0; // 当指针相遇时所有柱子的蓄水量计算完毕 while (left right) { pre Math.max(pre, height[left]); suf Math.max(suf, height[right]); // 根据短板原理移动边界值较小的一端 if (pre suf) { // 左侧最大值是瓶颈计算当前 left 指针处的蓄水量 ans pre - height[left]; left; } else { // 右侧最大值是瓶颈计算当前 right 指针处的蓄水量 ans suf - height[right]; right--; } } return ans; } }六、 复杂度极限分析1. 时间复杂度O(n)分析算法使用了相向双指针 left 和 right。在每次 while 循环的迭代中left 指针自增 1 或 right 指针自减 1。指针从数组两端出发直到重合时停止。每个元素仅被访问了一次总执行时间与数组长度 n 呈线性正比关系。2. 空间复杂度O(1)分析算法执行期间仅创建了 left、right、ans、pre、suf 共 5 个整型局部变量。所分配的内存空间不随输入数据规模 n 的扩大而增长空间开销为常数阶。