快来接青豆|「青训营 X 码上掘金」主题创作

165 阅读2分钟

当青训营遇上码上掘金

攒青豆


原题目

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


分析

725ef710a59944d49d0315bece7a1ac1_tplv-k3u1fbpfcp-zoom-in-crop-mark_3024_0_0_0.webp 以下为上图例子的解析: 输入:height = [5,0,2,1,4,0,1,0,3] 输出:17 解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。

以上图为例,我们可以一根一根柱子来分析能装下的青豆。

第一根柱子高度为5,它的左边最高的为0,右边最高的为4,看得出来,左右都没有比它高,故这个位置并不能装下任何青豆。

第二根柱子的高度为0,它的左边最高的为5,右边最高的为4,由图可知,它能装下4 - 0 = 4个单位青豆。

第三根柱子的高度为2,它的左边最高的为5,右边最高的为4,由图可知,它能装下4 - 2 = 4个单位青豆。

第五根柱子的高度为4,它的左边最高的为5,右边最高的为3,由图可知,4 > 3,它能装下0个单位青豆。

...

以此类推,我们可以发现,每个位置能装下的青豆取决于三个因素:左边最高的柱子长度,右边最高的柱子长度和当前位置柱子的长度。i 位置可装下的青豆数目为

min(maxLeft[i], maxRight[i]) - height[i]

且当当前位置的高度大于min(maxLeft[i], maxRight[i])时,min(maxLeft[i], maxRight[i]) - height[i]会得到一个负数,我们取0。

最后相加每个位置计算出来的值即可。

我们要遍历整个height数组,故时间复杂度为O(n), 需要存储每个位置的左最高,右最高,故空间复杂度为O(n)。


具体实现

package main

import (
	"fmt"
)

func main() {
	const LEN = 9 // 数组长度
	height := [LEN]int{5, 0, 2, 1, 4, 0, 1, 0, 3} // 高度数组
	var maxLeft, maxRight [LEN]int // 每个位置上左边最高的高度和右边最高的高度
	for i := 1; i < LEN; i++ {
		maxLeft[i] = Max(height[i - 1], maxLeft[i - 1])
		maxRight[LEN - i - 1] = Max(height[LEN - i], maxRight[LEN - i])
	}

	ans := 0
	for i:= 0; i < LEN; i++ {
		tmp := Min(maxLeft[i], maxRight[i]) - height[i]
		if tmp > 0 {// 如果青豆数大于0, 表示符合条件
			ans += tmp
		}
	}

	fmt.Println(ans)
}

// 返回两个数之间小的数
func Max(x, y int) int {
	if x < y {
		return y
	}
	return x
}

// 返回两个数之间大的数
func Min(x, y int) int {
	if x > y {
		return y
	}
	return x
}


引用

「青训营 X 码上掘金」主题创作活动入营版 开启! - 掘金 (juejin.cn)