一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
一、题目
leetcode 接雨水
给定 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
提示:
n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105
二、题解
方法一
可以理解为求数组中每个元素位置上所能承载的雨水数量,而对于每一个元素位置i,其所能承载的雨水数取决于其左边位置最大的高度leftMaxHeight和其右边位置最大的高度rightMaxHeight(可以包含本身位置i)中较矮的一个再减去位置i本身的高度。那么我们就可以遍历数组元素位置i,获取每一个元素位置i上的雨水数累加起来即可。但是由于获取左右两边位置的最大高度需要往两边循环查询,时间复杂度比较高,所以可以考虑空间换时间,预先记录下每一个位置i左右两边的最大高度是多少。具体的利用leftMaxHeight数组从左往右遍历记录左边位置最大高度,leftMaxHeight[i]表示height[i]的左边位置最大的高度是多少,那么leftMaxHeight[i]就应该为左边的最大高度和当前i的高度中较大的一个Math.max(leftMaxHeight[i - 1], height[i]),由于左边第一个元素的左边没有元素了,所以第一个元素的最大高度为自身高度。同理利用rightMaxHeight数组从右往左遍历记录右边位置最大高度,rightMaxHeight[i]表示height[i]的右边位置最大的高度是多少,那么rightMaxHeight[i]就应该为右边的最大高度和当前i的高度中较大的一个Math.max(rightMaxHeight[i + 1], height[i]),由于右边最后一个元素的右边没有元素了,所以右边最后一个元素的最大高度为自身高度。最后再循环数组元素height[i],获取当前位置承载的雨水为左右两边高度的较小值减去当前高度Math.min(leftMaxHeight[i], rightMaxHeight[i]) - height[i],最后遍历累加雨水总数返回即可。
三、代码
方法一 Java代码
class Solution {
public int trap(int[] height) {
int len = height.length;
// 求出每个位置i左边最大的高度
int[] leftMaxHeight = new int[len];
leftMaxHeight[0] = height[0];
for (int i = 1; i < len; i++) {
leftMaxHeight[i] = Math.max(leftMaxHeight[i - 1], height[i]);
}
// 求出每个位置i右边最大的高度
int[] rightMaxHeight = new int[len];
rightMaxHeight[len - 1] = height[len - 1];
for (int i = len - 2; i >= 0; i--) {
rightMaxHeight[i] = Math.max(rightMaxHeight[i + 1], height[i]);
}
int sumRain = 0;
for (int i = 0; i < len; i++) {
sumRain += Math.min(leftMaxHeight[i], rightMaxHeight[i]) - height[i];
}
return sumRain;
}
}
时间复杂度:O(n),一次循环记录左边最大高度,一次循环记录右边最大高度,一次循环记录雨水总数。
空间复杂度:O(n),一个数组记录元素左边最大高度,一个数组记录右边最大高度。
四、总结
方法一需要两个数组记录左右两边最大的高度,但是对于每一个位置只使用了数组的一个元素,所以可以考虑使用一个变量代替数组来记录。