Go语言-攒青豆

57 阅读2分钟

当青训营遇上码上掘金

题目

现有 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]--
			}
		}
	}

}

作者水平有限,如有错误,欢迎指正