开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情
题目描述
给定 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
解题思路
-
我们可以把陆地分成三个部分,左半边,中间,右半边。这三者的分界线就是最高点。如果只有一个最高点,就没有中间部分,以最高点为界分成左右两边。如果有多个相同的最高值,第一个最大值左、最后一个最大值右为为左右部分,中间的部分为中间部分。
-
有了这三部分我们可以分类讨论
- 对于左半部分,他是逐渐递增的,根据短板效应,从左向右短板不断提高。如果后面出现低于短板的值,我们就可以补上水。这就是一个for循环遍历即可。
- 对于中间部分,我们知道短板就是最高值,所以直接遍历补充即可。
- 对于右半部分他与左部分正好相反,利用相同的思路,我们从右向左遍历补水即可。
-
上面的思路只需要O(n)的时间复杂度。
func trap(height []int) int {
maxh := 0
for i := 0; i < len(height); i++ {
maxh = max(maxh, height[i])
}
// 计数左部分
ans := 0
l, r := 0, len(height)-1
tmpm := height[0]
for ; l < len(height); l++ {
if height[l] == maxh {
break
}
if height[l] < tmpm {
ans += tmpm - height[l]
}
tmpm = max(tmpm, height[l])
}
// 计算右部分
tmpm = height[len(height)-1]
for ; r >= l; r-- {
if height[r] == maxh {
break
}
if height[r] < tmpm {
ans += tmpm - height[r]
}
tmpm = max(tmpm, height[r])
}
// 计算中间
for ; l <= r; l++ {
if height[l] < maxh {
ans += maxh - height[l]
}
}
return ans
}