当青训营遇上码上掘金之攒青豆的大聪明

117 阅读2分钟

当青训营遇上码上掘金,一场攒青豆的饕餮大戏即将上演。

攒青豆的容器不一般,左右高低不太平,活像一个俄罗斯方块的方块,总之如下图所示:

image.png

怎么个攒法也很简单,如下文所示:

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

那么怎么快捷高效地计算出大聪明能攒多少青豆呢?

一个朴素的想法,把每一格能攒到的青豆加起来,就是能攒的青豆的总数了。

那每一个格子的青豆数怎么算呢?

仔细想想也不难发现,每一个格子上能接的总数,是其左右两个方向上最高的柱子中较矮的那个减去自身高度的数值。(最左端的格子左边最高的柱子高度设置为该格子的高度,最右端同理)

一个朴素的算法,遍历每一个格子,再分别从左向右遍历得出每一个格子左右两侧的最高柱子,再比较二者的大小,将较小者与该格子的高度相减,再把结果加到攒得的青豆总数上,如此大聪明的算法要耗费O(n^2)的复杂度。

那么还能不能再加速呢?

其实我们聚焦在每一个格子上再向两边扩散其实是做了许多多余的工的。我们不如换一个思路。先考虑一边,譬如说左边吧,从左往右数,右边一个左边最高的柱子的值不就是它左边那个格子的该值和自身的值去做一个比较咩,取较大的那个便是了。从右边开数同理。那么谦虚、谨慎、明智的算法来了(看Script里的部分):