当青训营遇上码上掘金
主题4:攒青豆
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
我们竖着考虑每一列的青豆数量。很容易发现下面几个规律
- 当一个柱子的左边和右边有比他高的柱子的时候,该列能攒下来的青豆数是
该柱左侧最高的柱子和该柱右侧最高的柱子的小值 - 该柱子的高度 - 当一个柱子的左边或者右边没有比他高的柱子时,该列不能存下青豆
所以,我们只需要记录下每一列的左侧和右侧有没有比他高的柱子,比他高的柱子最高又是多高,就可以用min(lmax,rmax) - h算出该列能攒的青豆数量
于是我们维护每个下标从 最左边 到 该下标柱子 和从 最右边 到 该下标 最高的柱子是哪个就可以了。
如何维护呢? 从左到右我们比较lmax[i - 1] 和 height[i] 的大小,较大的那个就是柱子的高度了。
代码如下
int trap(vector<int>& height) {
int n = height.size();
vector<int>lmax(n),rmax(n);
for(int i=0;i<n;i++){
lmax[i] = max((i - 1 < 0 ? 0 : lmax[i - 1]),height[i]);
}
for(int i=n-1;i>=0;i--){
rmax[i] = max(((i + 1 > n - 1) ? 0 : rmax[i + 1]),height[i]);
}
int res = 0;
for(int i = 1; i < n - 1; i ++){
int tmp = min(rmax[i + 1],lmax[i - 1]);
if(tmp > height[i]) res += tmp - height[i];
}
return res;
}
时间复杂度O(N) 只需要常数次遍历数组,空间复杂度O(N) 我们需要和 height 同一数量级的空间来存放辅助数组 lmax 和 rmax的值。
当然,该题也有其他解法,由于题意可以转换为求该下标之后最高的柱子,符合单调栈的简单应用,可以构造一个递减的栈,每次当一个比当前栈内末尾元素大的元素将要进栈时,计算该空出的区域能够接的青豆数量。