当青训营遇上码上掘金
攒青豆
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
方法有很多,双指针啊,动态规划啊。我这边简单介绍一下栈的解法。
什么情况下,豆子可以被接到?很明显,假设0高度也是个墙,那么就至少要三堵墙才能接,假设有A高度,B高度,C高度,一定要满足A<B,B<C的条件。
从栈的角度考虑,因为没有元素会自动入栈,所以一定会有A高度,然后如果接下来的B高度大于A,那么A出来,B替换A,否则继续指针后移。
步骤就是:
-
当前高度小于等于栈顶高度,入栈,指针后移。
-
当前高度大于栈顶高度,出栈,计算出当前墙和栈顶的墙之间栈的多少,然后计算当前的高度和新栈的高度的关系,重复第 2 步。直到当前墙的高度不大于栈顶高度或者栈空,然后把当前墙入栈,指针后移。
关于计算豆子的问题,这边简单模拟一下。
就是首先5高度进来,然后0高度进来,2高度进来,这个时候2>0,这个时候怎么计算的呢?就是5和2之间的宽度为1,高度最小为2,又因为0高度的墙,所以有1*(2-0)的豆子加进来。然后2进来。这个时候栈里面有5和2。
然后1高度进来,4高度进来,发现大于1,那么4和2的宽度为1,高度最小为2,有1高度的墙,所以有1*(2-1)的豆子进来。这个时候栈里面还有5,2。然后继续判断,4大于2,那么4和5的宽度的宽度的宽度为3,高度最小为4,有2高度的墙,所以有3*(4-2)的豆子进来,然后4进来。这个时候栈里面有5和4。
接下来过程同理。
import java.util.*;
public class Main {
public static int get(int[] height) {
int ans = 0;
Deque<Integer> stack = new LinkedList<Integer>();
int n = height.length;
for (int i = 0; i < n; ++i) {
while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
int top = stack.pop();
if (stack.isEmpty()) {
break;
}
int left = stack.peek();
int currWidth = i - left - 1;
int currHeight = Math.min(height[left], height[i]) - height[top];
ans += currWidth * currHeight;
}
stack.push(i);
}
return ans;
}
public static void main(String[] args){
int[] height = new int[]{5,0,2,1,4,0,1,0,3};
System.out.println(get(height));
}
}