主题 4:攒青豆
题目:
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
测试用例:
输入: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;
}
}
总结
这道题就是接雨水的题目,对于接雨水的题目,做法有多种。可以参考力扣面的接雨水的题,里面有很多优质题解。