跳转至

42. 接雨水

题目

给定 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

题解1(双指针)

Go
func trap(height []int) int {
    left, right := 0, len(height) - 1
    leftMax, rightMax := 0, 0

    ans := 0
    for left < right {
        leftMax = max(leftMax, height[left])
        rightMax = max(rightMax, height[right])

        if leftMax < rightMax {
            ans += leftMax - height[left]
            left++
        } else {
            ans += rightMax - height[right]
            right--
        }
    }
    return ans
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}
Python
class Solution:
    def trap(self, height: List[int]) -> int:
        ans = 0
        left, right = 0, len(height) - 1
        left_max, right_max = 0, 0
        while left < right:
            left_max = max(left_max, height[left])
            right_max = max(right_max, height[right])
            if height[left] < height[right]:
                ans += left_max - height[left]
                left += 1
            else:
                ans += right_max - height[right]
                right -= 1
        return ans

复杂度

  • 时间复杂度: \(O(n)\),其中 \(n\)\(height\) 的长度。
  • 空间复杂度: \(O(1)\)

题解2(单调栈)

Go
func trap(height []int) (ans int) {
    st := []int{}
    for i, h := range height {
        for len(st) > 0 && h >= height[st[len(st)-1]] {
            bottomH := height[st[len(st)-1]]
            st = st[:len(st)-1]
            if len(st) == 0 {
                break
            }
            left := st[len(st)-1]
            dh := min(height[left], h) - bottomH // 面积的高
            ans += dh * (i - left - 1)
        }
        st = append(st, i)
    }
    return
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}
Python
class Solution:
    def trap(self, height: List[int]) -> int:
        ans = 0
        st = []
        for i, h in enumerate(height):
            while st and h >= height[st[-1]]:
                bottom_h = height[st.pop()]
                if not st:  # len(st) == 0
                    break
                left = st[-1]
                dh = min(height[left], h) - bottom_h  # 面积的高
                ans += dh * (i - left - 1)
            st.append(i)
        return ans

复杂度

  • 时间复杂度: \(O(n)\),其中 \(n\)\(height\) 的长度。
  • 空间复杂度: \(O(min(n, U))\),其中 \(U=max(height)−min(height)+1\)

参考