栈操作之单调栈II

        再看这篇文章之前,可以建议先看看栈操作之单调栈I,这次再分享一个关于单调栈的题。

接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:
在这里插入图片描述
注:图片转载自leetcode官网
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

class Solution {
    public int trap(int[] height) {
        Deque<Integer> stack = new ArrayDeque<>();
        int ans = 0;
        for(int i = 0;i < height.length;i++){
            if(stack.isEmpty() || height[stack.peek()] >= height[i]){
                stack.push(i);
            }else{
                while(!stack.isEmpty() && height[stack.peek()] < height[i]){
                    int mid = stack.pop();
                    if(!stack.isEmpty()){
                        int w = i - stack.peek() - 1;
                        int h = Math.min(height[stack.peek()], height[i]) - height[mid];
                        ans += w * h;
                    }
                }
                stack.push(i);
            }
        }
        return ans;
    }
}

         以[0,1,0,2,1,0,1,3,2,1,2,1]为示例,说明上述代码的执行过程。首先定义了一个栈,之后定义了一个ans用于计算整个数组形成高度不一的柱子所能装的总的水的单位。
         进入for循环,遍历首个元素0,符合if判断中stack为空,将元素0的下标压入栈中,stack为[0],对应的值为[0]。之后遍历元素1,进入else,将栈中所有小于1的下标弹出,stack中0下标对应的值为0,小于1,弹出,mid的值为0,stack为空,因此不会进入if判断中。最后将元素1的下标压入栈中,stack为[1],对应的值为[1]。
         之后遍历元素0,0小于栈顶元素,因此将0对应的下标2压入栈中,stack为[2, 1],对应的值为[0, 1]。之后遍历元素2,进入else,将栈顶元素0对应的下标2弹出,mid = 2,值为0,i = 3,值为2,stack.peek() = 1,值为1。此时栈不为空,存在下标1,进入if,此时就开始计算这段区域能积累的水的单位,如下图红色框所示。w = 柱子高度为2的下标(当前下标i)减去柱子高度为1的下标(栈顶下标)-1,也就是w = 3 - 1 - 1 = 1。形成水的宽就是1,高就是两侧柱子高度的最小值减去中间柱子的高度,中间柱子高度就是mid指向的元素,就是0,一侧高度是1,另一侧高度是2,最小值是1,所以h就是1-0=1,形成水的单位就是1 * 1 = 1。ans += 1。ans = 1。if条件结束。stack为[1],值为[1]。此时栈不为空,且下标1对应值1小于2,还需要接着while循环,将下标1弹出,但是由于stack为空,不会进入if判断。最后将下标3压入栈中,stack为[3],对应的值为[2]。
在这里插入图片描述
         之后遍历元素1,1小于2,对应下标压入栈中,此时stack为[4, 3],对应的值为[1, 2],之后遍历元素0,0小于1,对应下标压入栈中,此时stack为[5, 4, 3],对应的值为[0, 1, 2],之后遍历元素1大于0,所以需要将下标5出栈,mid等于5,值为0,i等于6,值为1,stack.peek()等于4,值为1。w = 6 - 4 - 1 = 1,h = min(1, 1) - 0 = 1,ans += 1,ans等于2。其实这就是在计算如下图红色框中所示水的单位。此时stack为[4, 3],对应的值为[1, 2],栈顶元素值1不小于1,while循环结束。之后将元素1对应的下标6压入栈中,stack为[6, 4, 3],对应的值为[1, 1, 2]。
在这里插入图片描述
         之后遍历元素3,3大于栈顶下标6对应的元素1,将栈顶下标6弹出,此时mid = 6,值为1,stack.peek() = 4,值为1,i = 7,值为3,w = 7 - 4 - 1 = 2,h = min(3, 1) - 1 = 0,ans += 0,ans的值为2。stack为[4, 3],对应的值为[1, 2]。3大于1,while循环继续,mid = 4,值为1,i = 7,值为3,stack.peek()等于3,值为2,w = 7 - 3 - 1 = 3,h = min(3, 2) - 1 = 1。ans += 3,ans值为5,这部分其实就是在计算如下图所示区域水的单位。此时stack为[3],对应的值为[2]。3大于2,while循环继续,由于栈中仅剩下最后一个元素,不会进入if判断中。最后将元素3对应的下标压入栈中,此时stack为[7],对应的值为[3]。
在这里插入图片描述
         如此重复循环,遍历完整个数组,就可以得到最终答案为6。同时可以明显地观察到上述stack中存放下标对应的值总是升序的。

  • 39
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值