题目
给定 n
个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
输入:height = [4,2,0,3,2,5]
输出:9
分析思路1
对于每个位置,它能够接到的雨水量取决于左边的最高点和右边的最高点中较小的那个,再减去当前位置的高度。因此,我们可以先分别求出每个位置左边的最高点和右边的最高点,然后再遍历一遍数组,累加每个位置能够接到的雨水量即可。
题解1
class Solution {
public int trap(int[] height) {
int n = height.length;
int[] leftMax = new int[n];
int[] rightMax = new int[n];
// 因为第一个位置左边没有其他的位置,所以它的左边最高点就是自己
leftMax[0] = height[0];
// 同理,最后一个元素右侧最大值也是他自己
rightMax[n-1] = height[n-1];
// 从第二个元素开始循环
for(int i=1; i < n; i++){
leftMax[i] = Math.max(leftMax[i-1], height[i]);
}
// 从倒数第二个元素开始循环
for(int i=n-2; i >= 0; i--){
rightMax[i] = Math.max(rightMax[i+1], height[i]);
}
int ans = 0;
for(int i=0; i<n; i++){
ans += Math.min(leftMax[i], rightMax[i]) - height[i];
}
return ans;
}
}
执行结果
分析思路2
用一个单调递减栈,栈里存储的是数组下标。遍历数组时,如果当前的高度大于栈顶的高度,说明这个位置可以形成一个凹槽,需要计算它的面积。计算面积时需要先弹出栈顶元素,找到它的左边界和右边界,然后计算面积。
题解2
class Solution {
public int trap(int[] height) {
int n = height.length;
if (n < 3) {
return 0;
}
int ans = 0;
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < n; i++) {
while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
int bottom = stack.pop();
if (stack.isEmpty()) {
break;
}
int left = stack.peek();
int currHeight = Math.min(height[left], height[i]) - height[bottom];
int currWidth = i - left - 1;
ans += currHeight * currWidth;
}
stack.push(i);
}
return ans;
}
}
执行结果