1、力扣原题
https://leetcode-cn.com/problems/trapping-rain-water/
- 解题思路一: 动态规划
1.按列求,每一列能接多少雨水,取决于左右两边的大小
2.根据木桶效应,应该由左右两边最短的那个“墙”高度决定
class Solution {
public int trap(int[] height) {
int count = height.length;
int[] max_left = new int[count]; // 每个数组元素的值默认为0
int[] max_right = new int[count];
int result = 0;
for (int i = 1; i < count - 1; i++) { // 第i列,左边的一个高度 & 左边的一个的左边最高的,取最大值
max_left[i] = Math.max(max_left[i - 1], height[i - 1]);
}
for (int i = count - 2; i > 0; i--) { // 第i列,右边的一个高度 & 右边的一个的右边最高的,取最大值
max_right[i] = Math.max(max_right[i + 1], height[i + 1]);
}
for (int i = 0; i < count; i++) {
int min = Math.min(max_left[i],max_right[i]);
if (min > height[i]) {
result += min - height[i];
}
}
return result;
}
}
- 思路二:单调递减栈
1.墙的高度小于或等于前面的高度,说明当前不能接住雨水
2.墙的高度大于前面的高度,并且间距大于1,才能接住雨水
3.每次雨水的计算方法:墙的间距乘以高度(这个高度是左右两边最小值减去当前值)
class Solution {
public int trap(int[] height) {
int sum = 0;
Stack<Integer> mStack = new Stack<>();
for (int i = 0; i < height.length - 1; i++) {
mStack.push(i);
int rightVal = height[i+1]; // 右边的高度
while (!mStack.isEmpty() && height[mStack.peek()] < rightVal) {
int curVal = height[mStack.peek()]; // 当前的高度
mStack.pop();
if (mStack.isEmpty()) {
break; // 栈为空,停止本次计算
}
int distance = i - mStack.peek(); // 横轴之间的距离,即当前雨水的宽度
int leftVal = height[mStack.peek()]; // 左边的高度
int minVal = Math.min(leftVal,rightVal); // 取最小值
int h = minVal - curVal; // 雨水的高度
sum += h * distance; // 计算雨水数量
}
}
return sum;
}
}