当青训营遇上码上掘金-攒青豆

49 阅读2分钟

当青训营遇上码上掘金-攒青豆

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

攒青豆.png

以下为上图例子的解析:

输入:height = [5,0,2,1,4,0,1,0,3]  
输出:17  
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。

题解

这道题其实就是Leetcode接雨水的变种,接雨水是一道非常典型的单调栈的问题。

1.当前高度小于等于栈顶高度,入栈,指针后移。

2.当前高度大于栈顶高度,出栈,计算出当前墙和栈顶的墙之间水的多少,然后计算当前的高度和新栈的高度的关系,重复第 2 步。直到当前墙的高度不大于栈顶高度或者栈空,然后把当前墙入栈,指针后移。

如此一来就可以解决问题。

import java.util.*;

class Main{
   public static void main(String[] args) {
        int[] heights = {5, 0, 2, 1, 4, 0, 1, 0, 3};
        System.out.println(trap(heights));
    }

    public static int trap(int[] height) {
        int n=height.length;
        int sum=0;
        Deque<Integer> stack=new ArrayDeque<>();
        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 w=i-left-1;
                int h=Math.min(height[left],height[i])-height[top];
                sum+=h*w;
            }
            stack.push(i);
        }
        return sum;
    }
}

这道题其实难度很大,我在Leetcode写的时候写了很久,长时间不写有点生疏了。这道题既然是一道单调栈的问题,我们就可以使用栈来模拟这一行为来完成我们的目的。而对于计算 current 指向墙和新的栈顶之间的水,根据图的关系,我们可以直接把这两个墙当做之前解法三的 max_left 和 max_right,然后之前弹出的栈顶当做每次遍历的 height [ i ]。水量就是 Min ( max _ left ,max _ right ) - height [ i ],只不过这里需要乘上两个墙之间的距离。具体看代码即可!