当青训营遇上码上掘金
主题 4:攒青豆
题目描述
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
(这个题和力扣某个题高度相似)
思路
考虑每一列,我们发现这一列装水的容量不仅取决于自己的高度(自己太高了突出去肯定没法接),也取决于自己周围的高度(两边低了也不行)
具体来看一个例子
考虑a柱子,它能接的容量取决于自己高度2,左边最高的5,右边最高的4,具体为min(maxLeft,maxRight)-curH=min(5,4)-2=4-2=2
同理,考虑b柱子,它能接的容量取决于自己高度1,左边最高的5(这里看高度为5的那个,而不是4),右边最高的3,具体为min(maxLeft,maxRight)-curH=min(5,3)-1=3-1=2
因此我们思路明确了,对于每一个柱子,它的容量等于min(两侧最大值)减去自己高度,即min(maxLeft,maxRight)-curH;如果自己比两侧最值还要大,说明凸出去了,就像图中的高度5一样,这时候它的容量是0
实现
方法1
最暴力的想法,对于每一根柱子,枚举两侧的最大值和最小值,代入表达式计算即可 时间复杂度,遍历每一个O柱子(n),对于每一个柱子需要遍历全部来求出最大值和最小值同样需要O(n) 总的时间复杂度O(n*n)
如何优化? 注意到每个柱子求左右最值的时候会重复遍历很多次数组,可不可以优化呢?
方法2
使用动态规划来对求最值的过程进行优化
maxL[i]代表考虑到第i个元素时,左侧的最值(不包含自己); maxL[i]=max(maxL[i-1],h[i-1]);
maxR[i]代表考虑到第i个元素时,右侧的最值(不包含自己); maxR[i]=max(maxR[i+1],h[i+1]);
这样预处理,就可以优化掉求最值的时间复杂度,总的时间复杂度为O(n)