LeetCode 42 接雨水:双指针解法详解

解题思路

这道题是经典的接雨水 问题。核心是计算每个柱子位置能积多少水:对于位置 i,它能积的水量 = min(左边最高柱子, 右边最高柱子) - height[i](如果为正)。

方法一:动态规划(预处理左右最大值)

  • 用两个数组 leftMax[i] 和 rightMax[i] 分别记录位置 i 左边和右边的最高高度。
  • 然后遍历一次计算每个位置的积水量。
  • 时间 O(n),空间 O(n)。

方法二:双指针(空间 O(1))

  • 利用双指针从两端向中间收缩,同时维护 leftMax 和 rightMax。
  • 每次移动较矮一侧的指针,因为该侧的积水量只由该侧的 leftMax 或 rightMax 与当前高度决定(较矮一侧的 max 已经确定是短板)。
  • 时间 O(n),空间 O(1)。

这里采用更优的双指针法。

Java 代码实现(双指针)

java 复制代码
class Solution {
    public int trap(int[] height) {
        // 边界情况:长度小于3时无法积水
        if (height == null || height.length < 3) {
            return 0;
        }
        
        int left = 0;                // 左指针
        int right = height.length - 1; // 右指针
        int leftMax = 0;            // 当前遍历过的左侧最高柱子
        int rightMax = 0;           // 当前遍历过的右侧最高柱子
        int totalWater = 0;         // 总积水量
        
        // 当左右指针未相遇时,持续计算
        while (left < right) {
            // 哪侧矮就处理哪侧,因为积水量由矮侧决定
            if (height[left] < height[right]) {
                // 左侧柱子较矮
                if (height[left] >= leftMax) {
                    // 当前柱子比左侧最高还要高,更新 leftMax,此时该柱子上方无法积水
                    leftMax = height[left];
                } else {
                    // 当前柱子低于左侧最高,说明可以积水
                    totalWater += leftMax - height[left];
                }
                left++; // 左指针右移
            } else {
                // 右侧柱子较矮(或相等)
                if (height[right] >= rightMax) {
                    // 当前柱子比右侧最高还要高,更新 rightMax
                    rightMax = height[right];
                } else {
                    // 可以积水
                    totalWater += rightMax - height[right];
                }
                right--; // 右指针左移
            }
        }
        
        return totalWater;
    }
}

关键点注释与解释

  • 双指针的核心思想 :积水的多少由两侧的"短板"决定。我们维护 leftMax(从左边看到当前位置的最高柱子)和 rightMax(从右边看到当前位置的最高柱子)。当 height[left] < height[right] 时,说明 leftMax 一定小于 rightMax(因为 rightMax 至少等于 height[right],而 height[right] > height[left])。此时 left 位置的积水量完全由 leftMax 决定,与右侧无关,因此可以先计算 left 处的水量,然后 left++。同理,右侧较低时,先处理右指针。
  • **为什么这样不会漏算?**我们每次都处理当前较矮的一侧,并且只依赖该侧的历史最大值。由于另一侧的柱子更高,保证了该侧的积水不会从另一端流走,因此计算的积水量是准确的。
  • 相等时移动哪边? height[left] == height[right] 时,移动哪边都可以,代码中归到了 else 分支(移动 right),不影响最终结果。
  • 复杂度分析:时间 O(n),每个元素最多访问一次;空间 O(1),只用了几个变量。

示例演示

以 height = [0,1,0,2,1,0,1,3,2,1,2,1] 为例:

步骤 left right heightleft heightright leftMax rightMax 操作 总水量
1 0 11 0 1 0 0 左矮,0<0? 更新leftMax=0,left++ 0
2 1 11 1 1 0 0 左矮,1>=0? 更新leftMax=1,left++ 0
3 2 11 0 1 1 0 左矮,0<1? 积水+1,left++ 1
4 3 11 2 1 1 0 右矮,处理右:1>=0? 更新rightMax=1,right-- 1
5 3 10 2 2 1 1 右矮,2>=1? 更新rightMax=2,right-- 1
6 3 9 2 1 1 2 右矮,1<2? 积水+1,right-- 2
7 3 8 2 2 1 2 右矮,2>=2? 更新rightMax=2,right-- 2
8 3 7 2 3 1 2 左矮,2>=1? 更新leftMax=2,left++ 2
9 4 7 1 3 2 2 左矮,1<2? 积水+1,left++ 3
10 5 7 0 3 2 2 左矮,0<2? 积水+2,left++ 5
11 6 7 1 3 2 2 左矮,1<2? 积水+1,left++ 6
12 7 7 相遇 - - - 结束 6

最终总水量为 6,与预期一致。

其他解法(动态规划)参考

如果追求思路简单,也可以用 O(n) 空间的方法:

java 复制代码
public int trap(int[] height) {
    if (height == null || height.length < 3) return 0;
    int n = height.length;
    int[] leftMax = new int[n];
    int[] rightMax = new int[n];
    
    leftMax[0] = height[0];
    for (int i = 1; i < n; i++) {
        leftMax[i] = Math.max(leftMax[i - 1], height[i]);
    }
    
    rightMax[n - 1] = height[n - 1];
    for (int i = n - 2; i >= 0; i--) {
        rightMax[i] = Math.max(rightMax[i + 1], height[i]);
    }
    
    int water = 0;
    for (int i = 0; i < n; i++) {
        int minBound = Math.min(leftMax[i], rightMax[i]);
        if (minBound > height[i]) {
            water += minBound - height[i];
        }
    }
    return water;
}

面试中常见法。

相关推荐
怕浪猫5 小时前
RAG 面试 6 连问,从原理到优化全部覆盖
python·算法·面试
无线通信科研笔记6 小时前
IEEE TVT 2026 论文精读与完整复现|相位误差如何重塑近场 RIS 的幅相响应
论文阅读·人工智能·python·算法·论文笔记
mmmmath_37 小时前
二叉树の递归遍历
算法
All for pursuit.7 小时前
【位运算-1】338.比特位计数
数据结构·c++·算法·leetcode
小师兄吃牛肉8 小时前
C语言中的nullptr有必要吗
c语言·c++·算法
一只小小的芙厨9 小时前
【线性DP】
学习·算法·动态规划
奋发向前wcx9 小时前
CSP-J复赛模拟赛5 王晨旭补题 2026.10.5
算法
罗湖老棍子11 小时前
C Looooops(信息学奥赛一本通- P1640)
算法·数论·同余·裴蜀定理·扩展欧几里得
Interview Aid11212 小时前
OpenAI SWE 面试流程
面试·职场和发展
我命由我1234512 小时前
Photoshop - Photoshop 使用对齐功能定位元素
学习·职场和发展·产品运营·求职招聘·职场发展·产品经理·学习方法