题目
解答
class Solution {
public int trap(int[] height) {
if (height.length <= 1) {
return 0;
}
int sum = 0;
Stack<Integer> stack = new Stack();
stack.push(0);
for (int i = 1; i < height.length; i ++) {
while (!stack.empty() && height[i] > height[stack.peek()]) {
// 如果当前元素比栈顶的元素大, 计算一次水量
int index = stack.pop();
if (stack.empty()) {
break;
}
int preHeight = height[stack.peek()];
int area = (i - stack.peek() - 1) * (Math.min(preHeight, height[i]) - height[index]);
sum += area;
}
stack.push(i);
}
return sum;
}
}
思路1
(1) 每个位置能接雨水的值, 等于当前位置向左一直寻找的最大值leftMax, 和当前位置向右一直寻找的最大值rightMax有关. 能接的值 = Math.min(leftMax, rightMax) - height[i]
就是积蓄的雨水在当前位置的积水量
(2) 枚举完所有位置, 每次枚举都需要向左, 向右找, 枚举完后, 就得到能接雨水的值
思路2
(1) 利用一个栈, 从左往右遍历数组, 遇见比栈顶元素小的(空的时候就直接添加), 就将数组元素的下标入栈.
(2) 栈中的元素顶部的就是最后添加的元素, 一旦当前元素比栈顶的元素大, 就表明可以进行一次雨水量的计算了.
假设栈里本身是A, B ,C 当前的元素是D, 当D > C时, 将C 弹出, 根据此时的栈顶B和当前元素D就像故意再加上弹出的C就可以计算出C位置的积水量了 = (Math.min(B, D) - h[C]) * (B - D -1)
注意一定要记得减去h[C]
然后就得到了C处的一部分水量, 注意, 一定是一部分.
然后D和B比, 如果D比B大, 同样的弹出B, 然后D和A加上B, 计算一次水量, 注意这里D和A之间的距离就不再是1了, 因为计算出来的水量是横着的一列, 就是在这里, 计算得到的水量, 有一部分就是属于C位置的水量.
也就是下图中1区域就是弹出C的时候计算的水量, 2区域就是弹出B的时候计算的水量
(3) 当步骤2中, A也弹出后, 无法计算水量, 因为栈顶没有元素了, 此时将D入栈, 继续遍历数组元素, 最后直到数组遍历完毕.