题目描述
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
题解
单调递减栈方法
- 明确单调栈方法是按照行来统计雨水数量的。
- 单调栈中存的数据是
下标
- 思路就是找到当前节点两侧第一个比它高的位置,计算行当前能装多少水,举例:
比如我们要求这一块雨水的体积。
遇到123的时候,由于都是递减的,直接入栈就好,此时状态应该是:
当遇到4了,比栈顶元素高
,所以栈顶元素3出栈。此时状态应该如下:
其实此时已经找到了3左右两边第一个比它高的元素,左边比3高的元素为栈顶的2
,右边比3高的元素为遍历遇到的4
。那么此时第一块雨水的体积已经可以算出来了,就是:
//宽:右边坐标-左边的坐标 - 1 即:4 - 2 - 1。 高:两边较小的高度 - 当前的高度
//体积 = 宽 * 高
(i - deque.peekLast() - 1) * (Math.min(height[i], height[deque.peekLast()]) - height[tmp]);
计算完第一块体积后,发现4的高度和栈顶2的高度一样,此时4可以不入栈(入栈也没事儿,入栈后的情况,遇到5时,4弹栈,此时栈顶元素和4高度相同所以计算高的时候,高:两边较小的高度 - 当前的高度
= 0,所以计算出来的体积也是0,对结果没有影响。所以入不入栈都可以,为了代码简洁,就按照入栈讲解了)。
遍历到5的时候,4弹栈,计算出体积为0。然后5还比栈顶元素2高,所以2弹栈,此时状态为
此时就可以计算第2块雨水的体积,同样是宽 * 高
。
宽:右边坐标-左边的坐标 - 1 即:5 - 1 - 1
。 高:两边较小的高度 - 当前的高度 即:min(2, 3) - 1
累加到res上。
完整代码:
class Solution {
public int trap(int[] height) {
Deque<Integer> deque = new LinkedList<>();
int res = 0;
for (int i = 0; i < height.length; i++){
//遇到比栈顶大的元素
while (!deque.isEmpty() && height[i] > height[deque.peekLast()]){
int tmp = deque.pollLast();
if (!deque.isEmpty()){
//根据栈顶元素,弹栈出来的tmp,和遍历遇到的i,计算这一块的体积
res += (i - deque.peekLast() - 1) * (Math.min(height[i], height[deque.peekLast()]) - height[tmp]);
}
}
deque.add(i);
}
return res;
}
}