【题目】42. 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。
示例:
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
【解题思路1】按列求
- 查找左边最高的墙
- 查找右边最高的墙
- 这一列的雨水就是两边较矮的最高的墙减去自己的高度
class Solution {
public int trap(int[] height) {
int sum = 0;
//两端肯定不会有雨水
for(int i=1; i<height.length-1; i++){
//查找左边最高的墙,需要查找到最左端
int max_left = 0;
for(int j=i-1; j>=0; j--){
if(height[j] > max_left){
max_left = height[j];
}
}
//查找右边最高的墙,需要查找到最右端
int max_right = 0;
for(int j=i+1; j<height.length; j++){
if(height[j] > max_right){
max_right = height[j];
}
}
//这一列的雨水就是两边较矮的最高的墙减去自己的高度
int min_max = Math.min(max_left, max_right);
if(min_max > height[i]){
sum += (min_max - height[i]);
}
}
return sum;
}
}
【解题思路2】动态规划
用数组记录左右两边最高的墙,减少遍历次数
数组max_left [i] 代表第 i 列左边最高的墙的高度,数组max_right[i] 代表第 i 列右边最高的墙的高度,都不包括自身。
- max_left [i] = Max(max_left [i-1],height[i-1])
- max_right[i] = Max(max_right[i+1],height[i+1])
class Solution {
public int trap(int[] height) {
int sum = 0;
int[] max_left = new int[height.length];
int[] max_right = new int[height.length];
for (int i = 1; i < height.length - 1; i++) {
max_left[i] = Math.max(max_left[i - 1], height[i - 1]);
}
for (int i = height.length - 2; i >= 0; i--) {
max_right[i] = Math.max(max_right[i + 1], height[i + 1]);
}
for (int i = 1; i < height.length - 1; i++) {
int min = Math.min(max_left[i], max_right[i]);
if (min > height[i]) {
sum = sum + (min - height[i]);
}
}
return sum;
}
}
【解题思路3】双指针
官方题解有动图
虽然只需要遍历一次,但是不如上面两个数组存储max值直观
class Solution {
public int trap(int[] height) {
int sum = 0;
int max_left = 0;
int[] max_right = new int[height.length];
for (int i = height.length - 2; i >= 0; i--) {
max_right[i] = Math.max(max_right[i + 1], height[i + 1]);
}
for (int i = 1; i < height.length - 1; i++) {
max_left = Math.max(max_left, height[i - 1]);
int min = Math.min(max_left, max_right[i]);
if (min > height[i]) {
sum = sum + (min - height[i]);
}
}
return sum;
}
}
【解题思路4】栈
class Solution {
public int trap(int[] height) {
int sum = 0;
Stack<Integer> stack = new Stack<>();
int cur = 0;
while(cur < height.length){
//cur比栈顶元素高时
while(!stack.empty() && height[cur] > height[stack.peek()]){
int h = height[stack.peek()]; //栈顶元素
stack.pop(); //出栈
if(stack.empty()){
break;
}
int distance = cur - stack.peek() - 1; //两堵墙之间的距离
int min = Math.min(height[stack.peek()], height[cur]);
sum = sum + distance * (min - h);
}
stack.push(cur);
cur++;
}
return sum;
}
}