1.题目描述
2. 题解
func trap(_ height: [Int]) -> Int {
var sum = 0
if height.count < 3 {
return 0
}
var maxLeft = [Int](repeating: 0, count: height.count)
var maxRight = [Int](repeating: 0, count: height.count)
for i in 1..<height.count-1 {
maxLeft[i] = max(maxLeft[i - 1], height[i - 1])
}
for i in (0...height.count - 2).reversed() {
maxRight[i] = max(maxRight[i + 1], height[i + 1])
}
for i in 1..<height.count - 1 {
let h = min(maxLeft[i], maxRight[i])
if h > height[i] {
sum = h - height[i] + sum
}
}
return sum
}
3. 思路
- 按当前列去求
- 剪枝操作
(a)当数组的个数小于3个的时候,结果为0 - 当前列能接的雨水个数,取决于左边柱子和右边柱子的最矮的那个柱子
(a)所以需要求左边和右边最小的柱子
(b)数组的第一个和最后一个,永远无法接到雨水,可以排除在外
(c)比如求第1列(按下标为1来)的时候,那么第1列的左边最高的柱子,为第0列柱子和前面0根柱子的最大值。
举例: height = [4,2,5,3,2,4]
先定义:var maxLeft = [Int](repeating: 0, count: height.count)
转换为代码:
maxLeft[1] = max(height[0], maxLeft[0]) // max(4, 0) ==> 4
maxLeft[2] = max(height[1],maxLeft[1]) // max(2, 4) ==> 4
maxLeft[3] = max(height[2],maxLeft[2]) // max(5,4) ==> 5
maxLeft[4] = max(height[2],maxLeft[2]) // max(3,4) ==> 4
同理:var maxRight = [Int](repeating: 0, count: height.count)
maxRight[4] = max(height[5],maxLeft[5]) // max(4,0) ==> 4
maxRight[3] = max(height[4],maxLeft[4]) // max(2,4) ==> 4
maxRight[2] = max(height[5],maxLeft[4]) // max(3,4) ==> 4
maxRight[1] = max(height[5],maxLeft[4]) // max(5,4) ==> 5
当求第n个的时候:
// 求第一个位置的雨水
// 左边和右边的最矮的那个柱子为
//min(maxLeft[1],maxRight[1]) == max(4, 5) = 4
// 因为 height[1] == 2,小于最小的柱子4,那么这里能接的雨水为 4-2 = 2
// 求第二个位置的雨水
// 左边和右边的最矮的那个柱子为
//min(maxLeft[2],maxRight[2]) == max(4, 4) = 4
// 因为 height[2] == 5,大于于最小的柱子4,那么这里能接的雨水为 0
// 求第三个位置的雨水
// 左边和右边的最矮的那个柱子为
//min(maxLeft[3],maxRight[3]) == max(5, 4) = 5
// 因为 height[3] == 3,小于最小的柱子4,那么这里能接的雨水为 4-3 = 1
// 求第四个位置的雨水
// 左边和右边的最矮的那个柱子为
//min(maxLeft[4],maxRight[4]) == max(4, 5) = 4
// 因为 height[1] == 2,小于最小的柱子4,那么这里能接的雨水为 4-2 = 2
// ... 以此类推,求每个位置的雨水个数
// 再求和,就是最后的答案 :2 + 1 + 2 = 5