当青训营遇上码上掘金——攒青豆

68 阅读2分钟

当青训营遇上码上掘金

题目:攒青豆

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

攒青豆.png

以下为上图例子的解析:

输入:height = [5,0,2,1,4,0,1,0,3]  
输出:17  
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。

解析

这道题是经典的木桶效应。每一个位置上面的青豆数量取决于该位置左边的最高柱子的高度和该位置右边的最高柱子的高度,所以我们需要维护两个数组去记录每一个位置左边的最高柱子的高度和右边的最高柱子的高度。然后取两者的较小值,用该值减去当前位置的柱子高度,就可以得到当前位置的可以放的青豆数量。这样的时间复杂度就是O(n)。

怎样求当前位置左(右)边最高柱子的高度?

n := len(height)
//dpl[i]表示i左边(包括i)的最高高度
dpl := make([]int, n)
//dpr[i]表示i右边(包括i)的最高高度
dpr := make([]int, n)
dpl[0] = height[0]
dpr[n-1] = height[n-1]
max := dpl[0]
for i := 1; i < n; i++ {
   if height[i] > max {
      max = height[i]
   }
   dpl[i] = max
}

max = dpr[n-1]
for i := n - 2; i >= 0; i-- {
   if height[i] > max {
      max = height[i]
   }
   dpr[i] = max
}

怎样求当前位置上可以放的青豆数量?

res := 0
for i := 0; i < n; i++ {
   var a int
   if dpl[i] < dpr[i] {
      a = dpl[i]
   } else {
      a = dpr[i]
   }
   //a - height[i]是每一个位置最多可以容纳的青豆
   res += a - height[i]
}

遍历加上每一个位置上可以放的青豆数量就是所有的青豆数量。

完整代码

package main

import "fmt"

func trap(height []int) int {
   n := len(height)
   //dpl[i]表示i左边(包括i)的最高高度
   dpl := make([]int, n)
   //dpr[i]表示i右边(包括i)的最高高度
   dpr := make([]int, n)
   dpl[0] = height[0]
   dpr[n-1] = height[n-1]
   max := dpl[0]
   for i := 1; i < n; i++ {
      if height[i] > max {
         max = height[i]
      }
      dpl[i] = max
   }

   max = dpr[n-1]
   for i := n - 2; i >= 0; i-- {
      if height[i] > max {
         max = height[i]
      }
      dpr[i] = max
   }

   res := 0
   for i := 0; i < n; i++ {
      var a int
      if dpl[i] < dpr[i] {
         a = dpl[i]
      } else {
         a = dpr[i]
      }
      //a - height[i]是每一个位置最多可以容纳的青豆
      res += a - height[i]
   }
   fmt.Println(res)
   return res
}

func main() {
   height := []int{5, 0, 2, 1, 4, 0, 1, 0, 3}
   trap(height)
}

总结

本题主要考察思维,仔细阅读题目,思考题目本质,即可得出解法。