攒青豆

57 阅读2分钟

当青训营遇上码上掘金。

今天我参与了「青训营 X 码上掘金」主题创作活动入营版 开启! - 掘金 (juejin.cn)这个活动,做了攒青豆这个题目,接下来分享一下我的解法。

问题描述

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

问题分析

通过题干可以知道这是一道接雨水问题(Trapping Rain Water),是一类经典的计算机算法问题,其主要问题是计算一组柱子在雨水下落时能够存储多少雨水。该问题涉及到双指针、动态规划等算法思想,是算法面试和竞赛中常见的考察内容。

为了解决这个问题,我们需要先对问题进行分析,根据问题的定义,我们可以知道一个柱子上能够存储的青豆数量是由该柱子左边和右边的最高柱子高度决定的,因此我们可以考虑维护每个柱子其左侧和右侧柱子的最大高度。

我们可以先遍历一遍数组,找出这些柱子中高度最高的柱子h,显然,位于柱子h左侧的柱子其右侧的最大高度等于h的高度maxH,位于柱子h右侧的柱子其左侧的最大高度等于h的高度maxH。所以我们接下来分别从数组的左端和右端开始扫描。在从左向右扫描的过程中,我们需要维护该柱子左侧的最大高度lh,如果当前柱子的高度大于lh,则更新lh,如果当前柱子的高度小于lh,则当前柱子能够积攒的青豆数量为lh-当前柱子的高度。对于从右向左扫描的过程,其操作原理相同。

算法实现

package main

import "fmt"

func zanQingDou(height []int) int {
    n:=len(height)
    maxIndex:=0
    maxH:=0
    // 先找到柱子的最大高度
    for i,v:=range height{
        if v>maxH{
            maxH=v
            maxIndex=i
        }
    }
    area:=0
    lh:=0
    // 从左遍历到高度最大的柱子,期间不断更新左边柱子的最大高度
    for i:=0;i<maxIndex;i++{
        if height[i]>lh{
            lh=height[i]
            continue
        }
        area+=lh-height[i]
    }
    rh:=0
    // 从右遍历到高度最大的柱子,期间不断更新右边柱子最大高度
    for i:=n-1;i>maxIndex;i--{
        if height[i]>rh{
            rh=height[i]
            continue
        }
        area+=rh-height[i]
    }
    return area

}

func main() {
    var nums []int=[]int{5,0,2,1,4,0,1,0,3}
    ret:=zanQingDou(nums)
    fmt.Println(ret)
}