主题 4:攒青豆

42 阅读1分钟

当青训营遇上码上掘金

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

image.png

这道题和接雨水是一道一模一样的题,因此我这里是直接copy的代码。

但是我引申一下,如果说柱子有正有负呢?该怎么去计算接豆子的个数呢?

1、先假设柱子全为正,求出柱子全为正,能接多少豆子

2、把每个负数高度柱子的绝对值加上去,得到最终的答案

步骤1 的思路:

  1. 先求出每个柱子左边的柱子中最高的柱子的高度
  2. 然后求每个柱子右边的柱子中最高的柱子高度
  3. 求出左右高度的柱子的最高高度意义是什么呢,当我遍历到i这个点,我求出i左右柱子高度的最大值的,最小值。再减去height[i]就能知道当前位置能装多少雨水。

image.png

通过这幅图也能看出,首先预处理左右柱子高度的最大值,然后进行On遍历,就能得到攒豆子的值。 当然这道题的原型是接雨水,只是改了个题面而已。

package main

import "fmt"

func main() {
  arr := []int{5,0,2,1,4,0,1,0,3}
  fmt.Println(trap(arr))
}

func trap(height []int) (ans int) {
    n := len(height)
    if n == 0 {
        return
    }

    leftMax := make([]int, n)
    leftMax[0] = height[0]
    for i := 1; i < n; i++ {
        leftMax[i] = max(leftMax[i-1], height[i])
    }

    rightMax := make([]int, n)
    rightMax[n-1] = height[n-1]
    for i := n - 2; i >= 0; i-- {
        rightMax[i] = max(rightMax[i+1], height[i])
    }

    for i, h := range height {
        ans += min(leftMax[i], rightMax[i]) - h
    }
    return
}

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

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