“当青训营遇上码上掘金”
在这次的「青训营 X 码上掘金」主题创作活动入营版,后端两道题中,选择了第四题。
题目
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
样例
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
思路分析
这道题有着一道Leetcode原题“接雨水”,这道题首先我们可以分析一下情况。首先我们所求的其实是平面上的情况,所以简化了情况之后其实只需要将每个点的高度进行分析,这样通过输入的height就可以对整个柱子模型进行建模。
青豆与柱子之间符合“木桶理论”,也就是说:木桶所能装的水取决于木桶的最短边。那么对于我们现在这些柱子来说,两根柱子可以组成一个桶形结构,那么问题来了,这么多柱子哪两根可以成为我们木桶的“边”呢?
问题很简单,当我们找到一个左边的时候,我们向平行高度的右边扫描过去,扫描到的第一个柱子即为能够形成桶形结构的情况。
思路纠正
经过实验后发现如果最左侧为最高柱子的话按上述思路将不会有匹配项,上述思路单方向扫描出现了一定的问题。
经过分析后我们发现,实际我们可以不从木桶结构的左侧/右侧出发,而是从桶内部出发,即通过当前所求列向左右两侧扫描,扫描到两个列高,即为桶的左右两端。
注意!扫描到左右两侧的列高要高于当前正处在的列的高度,否则不能形成“桶”形结构
算法设计
经过刚才的思路分析后情况已经明朗,只需按列求每列所能承装青豆数量即可,即当前列找左右两个柱子作为边界,取较短柱子高度为当前列能承受最多青豆数量,再减去当前列高度即可
//当前列能承装青豆数量:
contain = min(left,right)-cur;
再遍历整个输入数组即可
代码实现
本次代码采用Go语言实现,因为对于Go语言特性不是很熟悉,过程中有参考Leetcode接雨水官方题解
踩坑
注意Go语言官方Math库中没有实现对于int类型的比较大小函数,需要手动实现。
Go语言中数组为固定长度,若要使用非固定长度需要使用切片来实现相关功能。