leetcode热题题解-接雨水

Problem: 42. 接雨水


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

示例 1:

img

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

一、题目分析

这道题的目的是计算给定高度数组height中可以容纳的雨水总量。数组中的每个元素代表一个柱子的高度,我们需要找到这些柱子之间可以容纳的雨水。

二、解题思路

  1. 分别计算每个位置左侧和右侧的最大高度数组。
    • 首先,通过遍历数组从左到右计算每个位置左侧的最大高度,存储在maxLeft数组中。对于位置imaxLeft[i]height[0]height[i - 1]中的最大高度。
    • 然后,通过遍历数组从右到左计算每个位置右侧的最大高度,存储在maxRight数组中。对于位置imaxRight[i]height[i + 1]height[height.length - 1]中的最大高度。
  2. 计算每个位置可以容纳的雨水量并累加。
    • 对于每个位置i,可以容纳的雨水量等于其左侧和右侧最大高度中的较小值减去当前位置的高度。如果这个差值大于 0,则表示该位置可以容纳雨水,将其累加到总雨水量sum中。

三、代码解释

  1. public int trap(int[] height):这是一个公共方法,接受一个整数数组height作为参数,并返回可以容纳的雨水量。
  2. int sum = 0;:初始化总雨水量为 0。
  3. int[] maxLeft = new int[height.length];int[] maxRight = new int[height.length];:分别创建两个与输入数组长度相同的数组,用于存储每个位置左侧和右侧的最大高度。
  4. 第一个循环for(int i = 1; i < height.length; i++):从第二个位置开始遍历数组,计算每个位置左侧的最大高度,并存储在maxLeft数组中。
  5. 第二个循环for(int i = height.length - 2; i >= 0; i--):从倒数第二个位置开始遍历数组,计算每个位置右侧的最大高度,并存储在maxRight数组中。
  6. 第三个循环for(int i = 1; i < height.length - 1; i++):从第二个位置到倒数第二个位置遍历数组,计算每个位置可以容纳的雨水量。如果Math.min(maxLeft[i], maxRight[i]) - height[i]大于 0,则将其累加到sum中。
  7. return sum;:返回总雨水量。

四、时间复杂度和空间复杂度

  1. 时间复杂度:代码中有三个循环,每个循环都遍历了数组一次,所以时间复杂度为O(n) ,其中n是输入数组的长度。
  2. 空间复杂度:代码中创建了两个额外的数组maxLeftmaxRight,每个数组的长度与输入数组相同,所以空间复杂度为 O(n)。

五、执行详解

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

初始化阶段 计算左侧最大高度循环 计算右侧最大高度循环 计算雨水量循环 开始计算左侧最大高度 i = 1, maxLeft[1] = Math.max(maxLeft[0], height[0]), maxLeft[1]=0, 当前 maxLeft 数组为[0,0,...] i = 2, maxLeft[2] = Math.max(maxLeft[1], height[1]), maxLeft[2]=1, 当前 maxLeft 数组为[0,0,1,...] ... (继续处理每个 i 的值)直到循环结束, 当前 maxLeft 数组为[0,0,1,1,2,2,2,2,3,3,3,3] 完成左侧最大高度计算,开始计算右侧最大高度 i = height.length - 2 = 11, maxRight[11] = Math.max(maxRight[12], height[12]), maxRight[11]=1, 当前 maxRight 数组为[...,1] i = 10, maxRight[10] = Math.max(maxRight[11], height[11]), maxRight[10]=2, 当前 maxRight 数组为[...,2,1] ... (继续处理每个 i 的值)直到循环结束, 当前 maxRight 数组为[3,3,3,3,3,3,3,2,2,2,1,0] 完成右侧最大高度计算,开始计算雨水量 i = 1, diff = Math.min(maxLeft[1], maxRight[1]) - height[1], diff=-1,不增加 sum, 当前 sum = 0 i = 2, diff = Math.min(maxLeft[2], maxRight[2]) - height[2], diff=1,sum 增加 1, 当前 sum = 1 ... (继续处理每个 i 的值)直到循环结束, 当前 sum = 6 返回总雨水量 初始化阶段 计算左侧最大高度循环 计算右侧最大高度循环 计算雨水量循环

Code

class Solution {
    public int trap(int[] height) {
        int sum = 0;
        int[] maxLeft = new int[height.length];
        int[] maxRight = new int[height.length];
        for(int i = 1; i < height.length; i++) {
            maxLeft[i] = Math.max(maxLeft[i-1], height[i-1]);
        }
        for(int i = height.length - 2; i >= 0; i--) {
            maxRight[i] = Math.max(maxRight[i+1], height[i+1]);
        }

        for(int i = 1; i < height.length - 1; i++) {
            int diff = Math.min(maxLeft[i], maxRight[i]) - height[i];
            if(diff > 0) {
                sum += diff;
            }
        }
        return sum;
    }
}
  • 22
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值