当青训营遇上码上掘金
题目描述
-
####攒青豆
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
题解分析
先上代码:
package main
import "fmt"
func main() {
var total int = 0
var beans = []int{5, 0, 2, 1, 4, 0, 1, 0, 3}
total = calTotal(beans)
fmt.Println(total)
}
func calTotal(beans []int) int {
total := 0
right := len(beans)
if right == 1 || right == 2 {
return 0
}
for i, value := range beans {
leftMax, rightMax := max(beans, i)
if i == 0 || i == right-1 {
continue
}
if leftMax < rightMax {
total+=leftMax-value
}else {
total+=rightMax-value
}
}
return total
}
这题原题就在leetcode上,接雨水,需要用到简单的动态规划
求每一列能攒的青豆数,我们只需要关注当前列,左边最高的墙,右边最高的墙就够了。
青豆的数量,根据短板效应,我们只需要看当前柱子左边最高的柱子和右边最高的柱子中较矮的一个的高度。
所以,根据较矮的那个柱子和当前列的柱子的高度可以分为三种情况。
-
较矮的墙的高度大于当前列的墙的高度
很明显,较矮的一边,也就是左边的柱子的高度,减去当前列的高度就可以了。
-
较矮的墙的高度小于当前列的墙的高度
正在求的列不会有青豆,因为它大于了两边较矮的墙。
-
较矮的墙的高度等于当前列的墙的高度。
和上一种情况是一样的,不会有青豆留下。
明白了这三种情况,程序就很好写了,遍历每一列,然后分别求出这一列两边最高的墙maxl和maxr。找出较矮的一端,和当前列的高度比较,结果就是上边的三种情况。
对流程进行模拟: 如题目所示:(从左到右遍历)
[5,0,2,1,4,0,1,0,3]
第一步:5是柱子,不统计
第二步:0表示没有,右边最大的值为4
第三步:2,右边最大的值为4 小于左边最大的值5
第四步:1,左右边最大值的较小值为4
第五步:4 左右最大值的最小值为4
第六步:0 左右边最大值的较小值为3
第七步:1 左右边最大值的较小值为3
第八步: 0 左右边最大值的较小值为3
第九步:3 柱子,不统计
最后将其总数相加
以此类推,遍历整个数组就可以得出整个数组能接到多少青豆了。
代码思路
首先创建相关的变量
遍历不包含首尾的数组,创建一个计算左右最大值的函数,在遍历的同时每次都调用这个函数。并保存这两个的值,最后比较两个值的大小,用当前遍历的值减去两者的小值,最后再将其加上总数即可。