42. 接雨水

70 阅读2分钟

题目描述

题目链接

给定 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.length
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105

思路1

一个位置所能接的最大雨水量取决于两侧木板中最小的那个(柱子高度就是木板高度),因此求出每个位置左右侧木板的最大高度,然后使用两侧木板中高度较小的,减去柱子占去的雨水体积就是这个位置的最大储雨量。

其中左右侧木板的最大高度可以使用前后缀数组来求。

对于左侧木板,初始时等于最左侧木板的高度,随着从左到右移动的过程中,左侧木板的最大高度一直在发生变化;比较当前高度和前一个位置最大木板高度取大者即可。

(为什么可以用之前左侧的木板高度作为其他位置的左侧木板高度?想象水的流动,水往左流的过程中,起决定作用的是左侧最高的那块挡板,水漫出去后就算不上储雨量了,比如一个位置左侧最大木板高度为 3,而当前的位置的雨量为 4,那么高度为 4 的那个单位的雨量一定会漫出去,最终只能存储 3 个单位的雨量)

右侧木板同理。

代码

func trap(height []int) int {
    var prefix, suffix []int
    var n, ans int
    n = len(height)
    // 1. 每个位置左右侧木板最大高度
    prefix, suffix = make([]int, n), make([]int, n)
    prefix[0], suffix[n-1] = height[0], height[n-1]
    for i := 1; i < n; i++ {
        prefix[i] = max(prefix[i-1], height[i])
    }
    for i := n-2; i >= 0; i-- {
        suffix[i] = max(suffix[i+1], height[i])
    }
    // 2. 每个位置的最大储雨量累积
    for i := 0; i < n; i++ {
        ans += min(prefix[i], suffix[i])-height[i]
    }
    // 3. 返回结果
    return ans
}

图示

image.png

思路 2

代码

func trap(height []int) int {
    var lMaxBaffle, rMaxBaffle int
    var l, r, ans int
    l, r = 0, len(height)-1
    
    for l < r {
        lMaxBaffle, rMaxBaffle = max(lMaxBaffle, height[l]), max(rMaxBaffle, height[r])
        // 木桶原理
        if lMaxBaffle < rMaxBaffle {
            ans += lMaxBaffle-height[l]
            l++
        } else {
            ans += rMaxBaffle-height[r]
            r--
        }
    }
    
    return ans
}

图示

image.png