当青训营遇上码上掘金
题目
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
分析
- 这个题目和木桶装水一样,高度取决于最短的那个木板。只不过这里面的木桶有多个,且并排放置。
- 因此由于木桶效应,青豆的高度取决于最短的那个柱子。
- 我们观察每一层(将这一层当作最下面的一层,高度从这一层算),可以发现所有的青豆都被两根柱子夹住,所以我们可以从下面向上逐层查看,找到两个连续的柱子,将柱子之间的青豆累加,即可算出最终的青豆数。
- 逻辑已经清晰,剩下就是编写代码
代码逻辑
循环以下逻辑:
- 计数高度不为0的柱子
- 如果高度不为0的柱子数量小于等于1,则不可能放得下新的青豆,直接返回总数
- 查找第一个高度不为0的柱子
- 从这个柱子向后查找第一个高度不为0的柱子,将这两个柱子之间的青豆累加到总数中(两个柱子的下标相减再减一)
- 将所有高度不为0的柱子削减一层(减一)
具体代码
package main
import "fmt"
func main() {
var b []uint = []uint{5, 0, 2, 1, 4, 0, 1, 0, 3}
// 代码输出 17
fmt.Println(beens(b))
}
func beens(height []uint) int {
var total int = 0
for {
var notZero = 0
for _, v := range height {
if v > 0 {
notZero++
}
}
if notZero <= 1 {
return total
}
// 找到第一个非零的
i := 0
for ; i < len(height)-1; i++ {
if height[i] > 0 {
break
}
}
// 找这一层能放多少青豆
for i < len(height)-1 {
if height[i] != 0 {
j := i + 1
for ; j < len(height); j++ {
if height[j] != 0 {
total += j - (i + 1)
break
}
}
i = j
} else {
i++
}
}
// 将所有削减一层
for i := 0; i < len(height); i++ {
if height[i] > 0 {
height[i]--
}
}
}
}
作者水平有限,如有错误,欢迎指正