【LeetCode Hot100】接雨水 动态规划 vs 双指针,Java实现!图解+代码,小白也能秒懂!

💻 [LeetCode Hot100] 接雨水 动态规划 vs 双指针,Java实现!图解+代码,小白也能秒懂!

✏️本文对应题目链接:接雨水


📌 题目描述

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

示例:

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:可以接6个单位的雨水(蓝色部分表示雨水)。

🧠 解题思路(图文分解)

❗ 核心难点

如何高效计算每个位置能接的雨水量?


方法一:动态规划(黄金思路)✨

关键步骤:

  1. 预处理
    • 从左到右遍历,记录每个位置左侧的最大高度 leftMax
    • 从右到左遍历,记录每个位置右侧的最大高度 rightMax
  2. 计算雨水量
    • 每个位置能接的雨水量 = min(leftMax[i], rightMax[i]) - height[i]
    • 如果结果为正,则累加到总雨水量中

图解动态规划

输入数组:

height = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]

步骤1:计算 leftMax(从左到右)

leftMax[0] = height[0] = 0
leftMax[1] = max(leftMax[0], height[1]) = max(0, 1) = 1
leftMax[2] = max(leftMax[1], height[2]) = max(1, 0) = 1
leftMax[3] = max(leftMax[2], height[3]) = max(1, 2) = 2
...
leftMax = [0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3]

步骤2:计算 rightMax(从右到左)

rightMax[11] = height[11] = 1
rightMax[10] = max(rightMax[11], height[10]) = max(1, 2) = 2
rightMax[9] = max(rightMax[10], height[9]) = max(2, 1) = 2
rightMax[8] = max(rightMax[9], height[8]) = max(2, 2) = 2
...
rightMax = [3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 1]

步骤3:计算每个位置的雨水量

雨水量[i] = min(leftMax[i], rightMax[i]) - height[i]
例如:
i=2: min(1, 3) - 0 = 1
i=4: min(2, 3) - 1 = 1
i=5: min(2, 3) - 0 = 2
...
总雨水量 = 1 + 1 + 2 + 1 + 1 = 6

🚀 代码实现

class Solution {
    public int trap(int[] height) {
        if (height == null || height.length == 0) {
            return 0;
        }

        int n = height.length;
        int[] leftMax = new int[n]; // 记录每个位置左侧的最大高度
        int[] rightMax = new int[n]; // 记录每个位置右侧的最大高度

        // 从左到右计算leftMax
        leftMax[0] = height[0];
        for (int i = 1; i < n; i++) {
            leftMax[i] = Math.max(leftMax[i - 1], height[i]);
        }

        // 从右到左计算rightMax
        rightMax[n - 1] = height[n - 1];
        for (int i = n - 2; i >= 0; i--) {
            rightMax[i] = Math.max(rightMax[i + 1], height[i]);
        }

        // 计算总雨水量
        int totalWater = 0;
        for (int i = 0; i < n; i++) {
            totalWater += Math.min(leftMax[i], rightMax[i]) - height[i];
        }

        return totalWater;
    }
}

💡 复杂度分析

  • 时间复杂度:O(n) → 遍历数组三次
  • 空间复杂度:O(n) → 需要两个辅助数组 leftMaxrightMax

方法二:双指针法(优化空间复杂度)

关键思路:使用两个指针 leftright,动态维护左右最大高度,减少空间复杂度到O(1)。


图解双指针

初始状态:

height = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]
left = 0, right = 11
leftMax = 0, rightMax = 0
totalWater = 0

步骤1:height[left] < height[right]

left=0: height[0]=0 < height[11]=1
leftMax = max(0, 0) = 0
totalWater += 0 - 0 = 0
left++ → left=1

步骤2:height[left] < height[right]

left=1: height[1]=1 < height[11]=1
leftMax = max(0, 1) = 1
totalWater += 1 - 1 = 0
left++ → left=2

步骤3:height[left] < height[right]

left=2: height[2]=0 < height[11]=1
leftMax = 1
totalWater += 1 - 0 = 1
left++ → left=3

步骤4:height[left] < height[right]

left=3: height[3]=2 > height[11]=1
rightMax = max(0, 1) = 1
totalWater += 1 - 1 = 0
right-- → right=10

最终结果:

totalWater = 6

🚀 代码实现

class Solution {
    public int trap(int[] height) {
        int left = 0, right = height.length - 1;
        int leftMax = 0, rightMax = 0;
        int totalWater = 0;

        while (left < right) {
            // 更新左右最大高度
            leftMax = Math.max(leftMax, height[left]);
            rightMax = Math.max(rightMax, height[right]);

            // 计算雨水量并移动指针
            if (height[left] < height[right]) {
                totalWater += leftMax - height[left];
                left++;
            } else {
                totalWater += rightMax - height[right];
                right--;
            }
        }

        return totalWater;
    }
}

💡 复杂度分析

  • 时间复杂度:O(n) → 只需遍历数组一次
  • 空间复杂度:O(1) → 仅使用常数空间

🌟 总结要点

动态规划核心思想:预处理每个位置的左右最大高度
双指针优化:空间复杂度降至O(1),适合大数据量
适用场景:区间最值问题、累积问题


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值