解析
一个位置上能存多少水,取决于 (左边边界 和 右边边界 的最小值) - 当前位置的高度。
因为短的边界控制着 水位的高度。
左边边界取决于 左边木板的最大值,因为低的木板存不住水,高的木板可以存的更多,同理,右边边界取决于 右边木板的最大值。
因此,问题变成了,一个位置上能存多少水,取决于 (左边木板最大值 和 右边木板最大值 的最小值) - 当前位置的高度。
这样代码会容易写很多,我们可以声明两个数组,一个存每个位置上左边木板的最大值,一个存每个位置上右边木板的最大值。然后循环数组,算出每个位置上可以存多少水,然后相加得到结果。
前后缀数组
func trap(height []int) int {
var (
res = 0
leftMaxArr = make([]int, len(height))
rightMaxArr = make([]int, len(height))
leftMax = 0
rightMax = 0
)
for i, v := range height {
leftMaxArr[i] = maxInt(v, leftMax)
leftMax = maxInt(leftMax, v)
}
for i := len(height) - 1; i >= 0; i-- {
rightMaxArr[i] = maxInt(rightMax, height[i])
rightMax = maxInt(rightMax, height[i])
}
for i, _ := range height {
res += minInt(leftMaxArr[i], rightMaxArr[i]) - height[i]
}
return res
}
func maxInt(x, y int) int {
if x > y {
return x
}
return y
}
func minInt(x, y int) int {
if x < y {
return x
}
return y
}
优化
从上面的解析中,可以发现一个规律:在某个位置上,如果左边木板的最大值<右边木板的最大值,或者 右边木板的最大值 < 左边木板的最大值,那么这个位置能存多少水是可以计算出来的。
即 存多少水 = 左边木板最大值 - 当前高度 或者 右边木板最大值 - 当前高度。
双指针
func trap(height []int) int {
var (
res = 0
left = 0
right = len(height) - 1
leftMax = 0
rightMax = 0
)
for left < right {
leftMax = maxInt(leftMax, height[left])
rightMax = maxInt(rightMax, height[right])
if leftMax < rightMax {
res += leftMax - height[left]
left++
} else {
res += rightMax - height[right]
right--
}
}
return res
}
func maxInt(x, y int) int {
if x > y {
return x
}
return y
}