解法一:暴力法
对于位置 i
,能够装的水为:
water[i] = min( // 盛水的高度取决于左右柱子的较小值
// 左边最高的柱子
max(height[0..i]),
// 右边最高的柱子
max(height[i..end])
) - height[i]
遍历每个位置,都计算一遍可以装的水量,求和即可。
func trap(height []int) int {
res := 0
for i:=0; i<len(height); i++{
l_max, r_max := 0, 0
// 找左边最高的柱子
for j := i; j>=0; j--{
l_max = max(l_max, height[j])
}
// 找右边最高的柱子
for j := i; j<len(height); j++{
r_max = max(r_max, height[j])
}
cur := min(l_max, r_max) - height[i]
res += cur
}
return res
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
解法二:备忘录优化
直接把左右最高柱子的高度都提前计算出来,就不需要在每个位置 i
都要计算 r_max
和 l_max
,避免了重复计算
func trap(height []int) int {
if len(height) == 0{
return 0
}
// 申请两个数组充当备忘录
l_max := make([]int, len(height))
r_max := make([]int, len(height))
// base case
l_max[0] = height[0]
r_max[len(r_max)-1] = height[len(height)-1]
// 从左向右计算每个位置 l_max
for i := 1; i < len(l_max); i++ {
l_max[i] = max(height[i], l_max[i-1])
}
// 从右向左计算每个位置 r_max
for j := len(r_max)-2; j>=0; j--{
r_max[j] = max(height[j], r_max[j+1])
}
// 计算接水量
res := 0
for i := 0; i <len(height); i++{
res += min(l_max[i], r_max[i]) - height[i]
}
return res
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
- 时间复杂度:O(n)
- 空间复杂度:O(n)
解法三:双指针
不需要用备忘录提前计算了,而是用双指针边走边算,节省下空间复杂度。
func trap(height []int) int {
if len(height) == 0{
return 0
}
left, right := 0, len(height)-1
l_max, r_max := 0, 0
res := 0
for left < right{
// l_max 记录 height[0...left] 中最高柱子的高度
l_max = max(l_max, height[left])
// r_max 记录 height[right...end] 的最高柱子的高度
r_max = max(r_max, height[right])
// 取左右高度较小的那个柱子计算
if l_max < r_max {
res += l_max - height[left]
left++
}else {
res += r_max - height[right]
right--
}
}
return res
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
- 时间复杂度:O(n)
- 空间复杂度:O(1)
分析:
对于下图,此时的 l_max
是 left
指针左边的最高柱子,但是 r_max
并不一定是 left
指针右边最高的柱子,这真的可以得到正确答案吗?
其实这个问题要这么思考,我们只在乎
min(l_max, r_max)
。对于上图的情况,我们已经知道 l_max < r_max
了,至于这个 r_max
是不是右边最大的,不重要。重要的是 height[i]
能够装的水只和较低的 l_max
之差有关