【单调栈】突破接雨水问题!

🚀个人主页:一颗小谷粒

🚀所属专栏:力扣刷题

很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~

目录

1.1 题目要求

1.2 算法思路

1.3 图解分析

1.4 Java代码实现

1.5 复杂度分析

1.6 算法运用场景


1.1 题目要求

leetcode42.接雨水 是一道可以使用单调栈来解答的经典题目,如下:

42. 接雨水 - 力扣(LeetCode)

很多小伙伴拿到题后毫无头绪,不知如何下手,今天博主通过 单调栈的方式 来带领大家一步步理解单调栈在此题中是如何运用的?如何通过使用单调栈来突破此题?

1.2 算法思路

1. 从左到右依次枚举右柱子,

2. 若栈不为空,右柱子的高度大于等于栈顶柱子的高度,则取出栈顶柱子作为中间柱子

3. 如果这时栈是空的,我们退出循环,因为还需要再找到一根柱子,也就是左边的柱子

4. 如果这时栈不为空,说明左柱子存在,三根柱子可以构成一个容器接水,那么此时的高度差就是左边柱子的高度和右边柱子的高度取一个最小值,再减去中间这根柱子的高度,宽就是左右两根柱子的距离 right - left -1

6. 最后把right加到栈中,枚举下一个右柱子,直到枚举结束,返回最终res

1.3 图解分析

以该图为例,我们需要定义一个栈为stack,右柱子为right,左柱子为left,中间柱子为mid,最终返回的结果,也就是盛水的多少res,那么具体要如何做呢?

总体思路: 

从左到右依次枚举右柱子,每次枚举都需要将right压入栈中,但在压栈之前,如果右柱子高度大于或等于栈顶柱子的高度,那么就从栈顶取出这个柱子并记录下来,也就是我们的中间柱子mid,此时再判断取出栈顶元素后的栈是非为空,若为空直接退出本次循环,因为我们还缺少一根柱子,也就是缺少左柱子,那么就无法构成一个容器来接水,若取出栈顶元素后的栈不为空,那么说明左柱子存在,我们就计算盛水面积 ( 宽 = right - left - 1;高 = 左/右柱子的最小高度 - 中间柱子的高度 )

图1:

right = 0 时,由于栈此时为空,所以将 right 压入栈中。

然后接着枚举右柱子,当right = 1 时,虽然栈不为空,但不满足当前柱子的高度大于或等于栈顶柱子的高度 ( height[right] >= height[stack.peek] ),所以继续将 right 压入栈中。

right = 2,right =3 时同样,不满足 height[right] >= height[stack.peek]  所以继续压栈。

图2:

right = 4 时,满足 height[right] >= height[stack.peek] 所以取出栈顶元素作为中间柱子,即mid = height[stack.pop] ,取出栈顶元素后栈不为空,则再将栈顶元素作为左柱子,即left = height[stack.peek], 高 h = min(height[2],height[4]) - mid,res = (right - left -1)*h

图3: 

重复图2的操作,这一轮  高 h = min( height[1] , height[4] ) - mid,res = (right - left -1)*h

此时的 mid 是从图2栈顶元素取出的

按照这样的思路一直执行到右柱子枚举完即可! 

1.4 Java代码实现

    public int trap(int[] height) {
        int res = 0;
        Deque<Integer> stack = new ArrayDeque<>();
        for (int right = 0; right < height.length; right++) {
            while (!stack.isEmpty() && height[right] >= height[stack.peek()]) {
                int mid = height[stack.pop()];
                if (stack.isEmpty()) {
                    break;
                }
                int left = stack.peek();
                int h = Math.min(height[right], height[left]) - mid;
                res = res + h * (right - left - 1);
            }
            stack.push(right);
        }
        return res;
    }

建议看完代码后再捋一遍图解分析,你可能就恍然大悟了! 

1.5 复杂度分析

时间复杂度:O(n),其中 n 为 height 的长度。虽然我们写了个二重循环,但站在每个元素的视角看,这个元素在二重循环中最多入栈出栈各一次,因此循环次数之和是 O(n),所以时间复杂度是 O(n)。
空间复杂度:O(min(n,U)),其中 U=max(height)−min(height)+1。注意,栈中没有重复元素,在 height 值域很小的情况下,空间复杂度主要取决于 height 的值域范围。

1.6 算法运用场景

如果我们发现要计算的内容,涉及到上一个或者下一个更大或者更小的元素,那么可以尝试用单调栈解决!



变好的过程都不太舒服,你会经历一段艰难的时光,低谷、焦虑、内耗、自我怀疑...但没关系,沉淀自有意义,终会迎来豁然开朗的一刻,请你努力,为了自己,祝我们都能上岸!

博主微信:g2279605572 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值