Problem: 42. 接雨水
给定
n
个非负整数表示每个宽度为
1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
输入: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
中可以容纳的雨水总量。数组中的每个元素代表一个柱子的高度,我们需要找到这些柱子之间可以容纳的雨水。
二、解题思路
- 分别计算每个位置左侧和右侧的最大高度数组。
- 首先,通过遍历数组从左到右计算每个位置左侧的最大高度,存储在
maxLeft
数组中。对于位置i
,maxLeft[i]
是height[0]
到height[i - 1]
中的最大高度。 - 然后,通过遍历数组从右到左计算每个位置右侧的最大高度,存储在
maxRight
数组中。对于位置i
,maxRight[i]
是height[i + 1]
到height[height.length - 1]
中的最大高度。
- 首先,通过遍历数组从左到右计算每个位置左侧的最大高度,存储在
- 计算每个位置可以容纳的雨水量并累加。
- 对于每个位置
i
,可以容纳的雨水量等于其左侧和右侧最大高度中的较小值减去当前位置的高度。如果这个差值大于 0,则表示该位置可以容纳雨水,将其累加到总雨水量sum
中。
- 对于每个位置
三、代码解释
public int trap(int[] height)
:这是一个公共方法,接受一个整数数组height
作为参数,并返回可以容纳的雨水量。int sum = 0;
:初始化总雨水量为 0。int[] maxLeft = new int[height.length];
和int[] maxRight = new int[height.length];
:分别创建两个与输入数组长度相同的数组,用于存储每个位置左侧和右侧的最大高度。- 第一个循环
for(int i = 1; i < height.length; i++)
:从第二个位置开始遍历数组,计算每个位置左侧的最大高度,并存储在maxLeft
数组中。 - 第二个循环
for(int i = height.length - 2; i >= 0; i--)
:从倒数第二个位置开始遍历数组,计算每个位置右侧的最大高度,并存储在maxRight
数组中。 - 第三个循环
for(int i = 1; i < height.length - 1; i++)
:从第二个位置到倒数第二个位置遍历数组,计算每个位置可以容纳的雨水量。如果Math.min(maxLeft[i], maxRight[i]) - height[i]
大于 0,则将其累加到sum
中。 return sum;
:返回总雨水量。
四、时间复杂度和空间复杂度
- 时间复杂度:代码中有三个循环,每个循环都遍历了数组一次,所以时间复杂度为O(n) ,其中
n
是输入数组的长度。 - 空间复杂度:代码中创建了两个额外的数组
maxLeft
和maxRight
,每个数组的长度与输入数组相同,所以空间复杂度为 O(n)。
五、执行详解
输入height = [0,1,0,2,1,0,1,3,2,1,2,1]
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;
}
}