题目:接雨水
给定 n 个非负整数表示每个宽度为 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 个单位的雨水(蓝色部分表示雨水)。
思路分析
首先明确
- 两个柱子之间才能存储雨水
- 首尾无法存储雨水
- 存储的雨水是以矮的柱子计算的(短板理论)
那就可以计算每个位置的雨水存储量是多少,不包括首尾
比如:
- 索引为 1 的位置,由于之前的柱子最大高度是0,所以无法存储
- 索引为 2 的位置,左侧最高的柱子高度是1,右侧最高的柱子高度是3,短板理论,取最短的柱子为
1
,减去当前的自身高度0
,就是1-0
,得出当前位置可以存储1
个单位的雨水。 - 依次推算,可以得出每次只需找到当前位置的左侧最高的柱子和右侧最高的柱子,取二者中较矮的柱子,减去当前位置的柱子高度,就是存储雨水的量了。
得出以下伪代码(获取当前位置的雨水量)
rain = min(leftMaxHeight, rightMaxHeight) - selfHeight
rain
雨水量leftMaxHeight
左边最高的柱子高度,rightMaxHeight
右侧最高的柱子高度selfHeight
当前位置的柱子高度
AC 代码
以下代码为 暴力解决
, 很明显有优化的空间。
function trap(height = []) {
if (height.length === 0) {
return 0
}
const n = height.length
// 结果
let res = 0
for (let i = 1; i < n - 1; i++) {
let l_max = 0 // 左边最高的柱子高度
let r_max = 0 // 右侧最高的柱子高度
for (let j = i; j < n; j++) {
// 找右边最高的柱子
r_max = Math.max(r_max, height[j])
}
for (let j = i; j >= 0; j--) {
// 找左边最高的柱子
l_max = Math.max(l_max, height[j])
}
res += Math.min(l_max, r_max) - height[i]
}
return res
}
总结
时间复杂度 O(N^2)
空间复杂度 o(1)
其实可以用双指针解决,会优化很多。