当青训营遇上码上掘金

115 阅读2分钟

主题 4:攒青豆

题目:

现有 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 个单位的青豆。

解题思路:

这道题和接雨水极其类似,确实不能说相似度100%,只不过是把雨水换成青豆了。这道题可以采用单调栈来计算能接的青豆的总量。

维护一个单调栈,单调栈中的元素从栈底到栈顶单调递减(栈中存放的是对应元素的下标)

遍历一遍数组,遍历到坐标i时,记栈顶元素为top,前面一个元素为left,显然,一定会有height[left] >= height[top]。那么当有一个凹槽出现的时候,这个区域就可以接雨水了。

该区域的高度为:i - left - 1

该区域的高度为:min(height[left], height[i]) - height[top]

为了得到left,需要将top出栈,计算完top能接的雨水后,left就变成了新的top,一直重复以上的操作,直到该栈为空。

java代码:

/**
* 支持 import Java 标准库 (JDK 1.8)
*/
import java.util.*;

/**
* 注意:目前 Java 代码的入口类名称必须为 Main(大小写敏感)
*/
public class Main {
   public static void main(String []args) {
     int[] height = {5, 0, 2, 1, 4, 0, 1, 0, 3};
     int ans = trap(height);
     System.out.println(ans);
   }

   public static int trap(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 Width = i - left - 1;
         int Height = Math.min(height[left], height[i]) - height[top];
         ans += Width * Height;
       }
       stack.push(i);
     }
     return ans;
   }
}

总结

这道题就是接雨水的题目,对于接雨水的题目,做法有多种。可以参考力扣面的接雨水的题,里面有很多优质题解。