当青训营遇上码上掘金
主题4:攒青豆
题目:
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 单位的青豆。
分析:
该题其实就是力扣中的一个经典例题 “接雨水” ,不过从雨水换成了青豆(还挺应景的)
解法:
动态规划
原理:
- 初始化
-
用ar[i]表示下标为i的元素值
-
用数组dpl[i] 记录下标为i的元素其左侧最大值。
-
用数组dpr[i] 记录下标为i的元素其右侧最大值。
以上三个数组的容量应比原数组大2,即最左侧与最右侧元素设为高度为0的值,以便于后续边界处理。
- 第一次遍历(从左至右)
- 此次遍历记录每个元素其左侧最大元素的值:
- 因为左侧元素的左侧最大元素值已记录在左侧元素的“备忘录”中,故仅需取该值与左侧元素值中的最大值即可。
伪代码如下:
dpl[i] =max(dpl[i-1] ,ar[i-1])
3. 第二次遍历(从右至左)
类似于第一次遍历
dpr[i] = max(dpr[i+1] ,ar[i+1])
4. 第三次遍历(从左至右)
此次遍历开始记录青豆数量
设x为该元素对应的青豆数量,sum为青豆总数, 伪代码如下:
x=min(dpl[i] ,dpr[i]) - ar[i]
若x小于0(即左右侧都比该位置的值更小)则将x置0
计算完此处的x值后,记录该位置青豆数量: sum+=x
以下为实际代码(golang)