双指针的方法攒青豆

63 阅读2分钟

当青训营遇上码上掘金

题目描述

现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)

方法分析

这题其实是和力扣上的接雨水那题一模一样,需要计算总体积,可以考虑把每一个柱子上面的青豆算出来,然后结果进行累加,就可以得到总的青豆数了

如下图所示:

image.png 0+4+2+3+0+3+2+3+0=17

计算每个柱子上的青豆数

因为底都是1,任何数乘1都等于本身,那么我们就可以用高度来代表青豆数了,那怎么计算每个柱子上的青豆数呢? 经过观察可以发现,最左边和最右边的柱子都不可能接到青豆,中间的柱子接到的青豆会是左右两边取最高的柱子,然后用比较矮的一边减去它自身的高度就是这个柱子所接到的青豆数了,如果矮的那一个柱子没有当前这个高也是接不到青豆的

代码分析

函数传入的切片用height表示

最左和最右两个柱子不可能接到青豆,所以遍历时(i表示对应的第几个柱子)

if i == 0 || i == len(height)-1 {
        continue
}

每个柱子左右两边对应的最高的柱子用lHight和rHight表示

for j := i-1; j >= 0; j-- { // 往左寻找最大值,右边也同理
        lHight = max(lHight,height[j])
   }

每个柱子上的体积我们可以用高度差h来表示,res表示所有青豆数

 // 左右最高当中取矮的减去当前的高度
        h := min(lHight,rHight) - height[i]
        lHight = 0 // 计算完后左右最高都要重置一下,以免对后面的便利数据造成影响
        rHight = 0
        if h > 0 { // 当前柱子比左右较矮的柱子高时才能接到青豆
            res+=h
        }

最终完整代码

func trap(height []int) int {
    lHight, rHight, res := 0, 0, 0
    for i := 0; i < len(height); i++{
        if i == 0 || i == len(height)-1 { // 第一列和最后一列是不接雨水的
            continue
        }
        // 找到左边最高的
        for j := i-1; j >= 0; j-- {
            lHight = max(lHight,height[j])
        }
        // 找到右边最高的
        for j := i+1; j < len(height); j++ {
            rHight = max(rHight,height[j])
        }
        // 左右最高当中取矮的减去当前的高度
        h := min(lHight,rHight) - height[i]
        lHight = 0
        rHight = 0
        if h > 0 {
            res+=h
        }
    }
    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
}