当青训营遇上码上掘金
题目:现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
一般这种题目都是使用单调栈算法进行计算。
单调递增栈:
在一个数组中针对每一个元素从它右边寻找第一个比它小的元素
在一个数组中针对每一个元素从它左边寻找第一个比它小的元素
单调递减栈:
在一个数组中针对每一个元素从它右边寻找第一个比它大的元素
在一个数组中针对每一个元素从它左边寻找第一个比它大的元素
单调栈的使用范围:找一个数组中左边第一个比它小/大的元素。
复杂度:因为每个元素最多各自进出栈一次,复杂度是O(n).
题目的关键解法就是如何寻找凹槽。
首先遍历height[]数组中的每一根柱子,int一个last初始化为0;然后寻找stack中比当前柱子矮的柱子,然后计算它们之间以stack。peek()-last为高,俩柱子之间距离为底边的矩形的面积 = (height[stack.peek()]-last)*(i-stack.peek()-1);
循环完后,stack中的栈顶元素应该是大于当前柱子的最矮的一个柱子,或者为空。
如果stack有元素,则再计算当前柱子与栈顶柱子之间的矩形(height[i]-last)*(i-stack.peek()-1);
遍历完成后,得到最终答案就是能放的豆子的数量。
具体代码如下:
/**
* 支持 import Java 标准库 (JDK 1.8)
*/
import java.util.*;
/**
* 注意:目前 Java 代码的入口类名称必须为 Main(大小写敏感)
*/
public class Main {
public static void main(String []args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[]height = new int[n];
for(int i=0;i<n;i++)height[i]=scanner.nextInt();
Stack<Integer>stack = new Stack<>();
int res = 0;
for(int i=0;i<n;i++){
int last = 0; //上一个被取出的柱子,初始值为0;
while(!stack.empty()&&height[stack.peek()]<=height[i]){
res+=(height[stack.peek()]-last)*(i-stack.peek()-1);//计算俩柱子之间的矩形面积
last = height[stack.pop()];
}
if(!stack.empty())res+=(height[i]-last)*(i-stack.peek()-1);//栈内第一个比当前柱子高的柱子,计算他俩之间的矩形面积。
stack.push(i);
}
System.out.println(res);
}
}