leetcode42 接雨水

题目

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例

leetcode42 接雨水_第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 个单位的雨水(蓝色部分表示雨水)。

解析

这道题可以有暴力法、动态规划法、单调栈法、双指针法等,由于上一道题是用的双指针,为了好记,这里也使用双指针法。
先贴一个讲的比较好的视频:视频讲解
这道题使用双指针,主要的思路是:比如上图中的最高的那块木板,左边的位置能解多少雨水,取决于它左边木板的最大高度,因为低于这个最大高度是会漏出去的。
基础版的双指针,需要两个额外的数组,一个存从左边开始到i的最大高度,一个存从右边开始的。计算的方法就是比较前一时刻的最大值和此刻的比较,然后取max。这个时候就有了两个数组,取min后和本身的数组比较,就是能接的最大容量

func trap(height []int) (ans int) {
    n := len(height)
    preMax := make([]int, n) // preMax[i] 表示从 height[0] 到 height[i] 的最大值
    preMax[0] = height[0]
    for i := 1; i < n; i++ {
        preMax[i] = max(preMax[i-1], height[i])
    }

    sufMax := make([]int, n) // sufMax[i] 表示从 height[i] 到 height[n-1] 的最大值
    sufMax[n-1] = height[n-1]
    for i := n - 2; i >= 0; i-- {
        sufMax[i] = max(sufMax[i+1], height[i])
    }

    for i, h := range height {
        ans += min(preMax[i], sufMax[i]) - h // 累加每个水桶能接多少水
    }
    return
}

func min(a, b int) int { if a > b { return b }; return a }
func max(a, b int) int { if a < b { return b }; return a }

如果不想开辟两个新组数,那么就使用两个单纯的指针,分别从左右开始遍历,那么此刻我们知道,比如左右都遍历了两个位置,那么中间位置的容量我们是不知道的,但是如果前缀最大值比后缀最大值小,那么左边木桶的容量就是前缀最大值的容量,算完后向右扩展;同理如果后缀最大值比前缀最大值小,那么右边这个木桶的容量就是后缀最大值的容量。。。

func trap(height []int) int {
    n := len(height)
    ans := 0
    left := 0
    right := n-1
    preMax := 0
    sufMax := 0
    for left <= right {
        preMax = max(preMax, height[left])
        sufMax = max(sufMax, height[right])
        if preMax < sufMax {
            ans += preMax - height[left]
            left++
        } else {
            ans += sufMax - height[right]
            right--
        }
    }
    return ans
}

func max(a, b int) int{
    if a > b {
        return a
    }
    return b
}

你可能感兴趣的:(#,leetcode数组系列,算法,数据结构,leetcode)