题目描述
给定 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.length1 <= n <= 2 * 1040 <= height[i] <= 105
思路1
一个位置所能接的最大雨水量取决于两侧木板中最小的那个(柱子高度就是木板高度),因此求出每个位置左右侧木板的最大高度,然后使用两侧木板中高度较小的,减去柱子占去的雨水体积就是这个位置的最大储雨量。
其中左右侧木板的最大高度可以使用前后缀数组来求。
对于左侧木板,初始时等于最左侧木板的高度,随着从左到右移动的过程中,左侧木板的最大高度一直在发生变化;比较当前高度和前一个位置最大木板高度取大者即可。
(为什么可以用之前左侧的木板高度作为其他位置的左侧木板高度?想象水的流动,水往左流的过程中,起决定作用的是左侧最高的那块挡板,水漫出去后就算不上储雨量了,比如一个位置左侧最大木板高度为 3,而当前的位置的雨量为 4,那么高度为 4 的那个单位的雨量一定会漫出去,最终只能存储 3 个单位的雨量)
右侧木板同理。
代码
func trap(height []int) int {
var prefix, suffix []int
var n, ans int
n = len(height)
// 1. 每个位置左右侧木板最大高度
prefix, suffix = make([]int, n), make([]int, n)
prefix[0], suffix[n-1] = height[0], height[n-1]
for i := 1; i < n; i++ {
prefix[i] = max(prefix[i-1], height[i])
}
for i := n-2; i >= 0; i-- {
suffix[i] = max(suffix[i+1], height[i])
}
// 2. 每个位置的最大储雨量累积
for i := 0; i < n; i++ {
ans += min(prefix[i], suffix[i])-height[i]
}
// 3. 返回结果
return ans
}
图示
思路 2
代码
func trap(height []int) int {
var lMaxBaffle, rMaxBaffle int
var l, r, ans int
l, r = 0, len(height)-1
for l < r {
lMaxBaffle, rMaxBaffle = max(lMaxBaffle, height[l]), max(rMaxBaffle, height[r])
// 木桶原理
if lMaxBaffle < rMaxBaffle {
ans += lMaxBaffle-height[l]
l++
} else {
ans += rMaxBaffle-height[r]
r--
}
}
return ans
}