首先,單獨來看每一個柱子,每一個柱子上邊能乘的雨水和三個東西有關係。左邊的最大值和右邊的最大值和自己的高度。用公式來表示就是:
curWater = Min(lMax, rMax) - curHeight
思路清晰了之後,這道題有很多解法。比如比較麻煩的方法先遍歷一遍找出最大值,之後在最大值左邊和右邊遍歷。最大值左邊的rMax就是這個最大值。這種方法需要遍歷兩遍。不是最優解。
還有一種方法是可以遍歷一遍就出結果的。那就是單調棧。
單調棧就是維護一個“頭重腳輕“的棧。如果有大於棧頂的元素進入則說明可以乘住雨水了。把小於當前元素的都pop出來。
棧中存儲的是數組元素的index。代碼如下:
public class Solution {
public int trap(int[] height) {
int res = 0;
if (height == null) {
return 0;
}
int len = height.length;
// 單調棧
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < len; i++) {
// 如果不單調的話那就持續pop
while (!stack.empty() && height[stack.peek()] < height[i]) {
Integer curIdx = stack.pop();
// 如果棧頂元素一直相等,那麼全都pop出去,只留第一個。
while (!stack.isEmpty() && height[stack.peek()] == height[curIdx]) {
stack.pop();
}
// 獲取棧數據的時候總要看是否爲空
if (!stack.empty()) {
Integer left = stack.peek();
res += (Math.min(height[left], height[i]) - height[curIdx]) * (i - left - 1);
}
}
// 單調的話就繼續push
stack.push(i);
}
return res;
}
}