代码分享|主题四攒青豆

34 阅读2分钟

当青训营遇上码上掘金

题目:现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)

一般这种题目都是使用单调栈算法进行计算。

单调递增栈:
在一个数组中针对每一个元素从它右边寻找第一个比它小的元素
在一个数组中针对每一个元素从它左边寻找第一个比它小的元素

单调递减栈:
在一个数组中针对每一个元素从它右边寻找第一个比它大的元素
在一个数组中针对每一个元素从它左边寻找第一个比它大的元素

单调栈的使用范围:找一个数组中左边第一个比它小/大的元素。

复杂度:因为每个元素最多各自进出栈一次,复杂度是O(n).

题目的关键解法就是如何寻找凹槽。

image.png 首先遍历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);

    }
}