• 使用单调栈解决接雨水问题——LeetCode 42 接雨水+单调栈说明


    题目内容

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

    示例 1:

    在这里插入图片描述

    输入: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 个单位的雨水(蓝色部分表示雨水)。

    示例 2:

    输入:height = [4,2,0,3,2,5]
    输出:9

    提示:

    n == height.length
    1 <= n <= 2 * 104
    0 <= height[i] <= 105

    来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/trapping-rain-water
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    解题思路

    这道题我一开始也是没有什么头绪,正准备看题解,结果看到单调栈标题,瞬间就懂了(有时候还真的是要多练习才能有一些敏锐度,我都没想到这个)。于是回过头来准备自己写这个。恬不知耻一些,这个也算大半个自己写的吧(doge)。

    其实单调栈对于这类问题来说几乎就是天作之合了,单调栈最好的用处就是寻找数组中离自己最近的,比自己大或者小的元素的位置,在这道题这里正好可以看一下积攒雨水的柱子的位置。

    我们先来看一下单调栈结构解决找元素位置问题,这个其实我们可以用O(n^2)来解决,但是单调栈的存在可以把这个问题优化到O(N)

    我们先说数组中没有重复值的情况,这样好理解一些。如果我们要找的是最近的比自己大的数,那么我们就需要确定一点,那就是单调栈是从大到小排列的(栈底到栈顶)。满足条件的时候,我们直接压栈,但是如果发现有不满足的了,就需要出栈了,然后弹出栈顶之后,他左边的比他大的就是栈里他下面那个,右边那个就是进栈未遂的数据。如果没有就是无,这里会一直出栈知道能够进栈为止。这里一个数据进出栈都只有一次,所以时间复杂度是O(N)

    回到题目,首先就是用单调栈实现对于每一个位置找左右比自己高的位置的脚标,这里需要注意的是,最好用脚标才入栈,因为脚标的信息和高度是包含关系,脚标信息更多一些。

    然后把所有能找到左右比自己高的位置存在map里,这里其实如果留心一些会发现我们的栈中还是有元素没有出来的,这个就不用管了,这个说明我们最右边有一个下坡的形态,是根本存不下水的。

    有了这个数据之后就好处理多了,直接遍历,计算两边柱子能提供的高度-本身的高度。不过在计算好了之后,记得要更新height的数据,不然的话因为存在嵌套关系,会导致结果出现问题。

    代码

    class Solution {
    public:
        int trap(vector<int>& height) {
            stack<int> dandiao;
            map<int,pair<int,int>> mp;
            for(int i=0;i<height.size();i++){
                
                if(dandiao.size()==0){
                    dandiao.push(i);
                }
                else{
                    if(height[dandiao.top()]>height[i]){
                        dandiao.push(i);
                    }
                    else{
                        while(height[dandiao.top()]<=height[i]){
                            int weizhi=dandiao.top();
                            dandiao.pop();
                            int ding=dandiao.size()==0?-1:dandiao.top();
                            if(mp.find(i)==mp.end()){
                                
                                mp[weizhi]=pair<int,int>(ding,i);
                            }
                            else{
                                mp[weizhi]=pair<int,int>(ding,i);
                            }
                            if(dandiao.size()==0){
                                break;
                            }
                        }
                        dandiao.push(i);
                    }
                }
            }
            cout<<mp.size()<<endl;
            int ans=0;
            for(int i=0;i<height.size();i++){
                cout<<i<<":"<<mp[i].first<<"  "<<mp[i].second<<endl;
                if(mp[i].first==-1){
                    continue;
                }
                int low=min(height[mp[i].first],height[mp[i].second]);
                cout<<low<<endl;
                for(int j=mp[i].first+1;j<mp[i].second;j++){
                    ans+=((low-height[j]>0)?low-height[j]:0);
                    height[j]=low;
                    cout<<ans<<endl;
                }
                
            }
            
            return ans;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
  • 相关阅读:
    性能测试面试题总结(答案全)
    文本分类之DPCNN的原理(Pytorch实现)
    麒麟KYLINIOS软件仓库搭建03-软件仓库添加新版本的软件包
    鸿鹄工程项目管理系统em Spring Cloud+Spring Boot+前后端分离构建工程项目管理系统
    安全、可靠、合规,华为云守护企业网站安全
    2023年【司钻(钻井)】及司钻(钻井)作业模拟考试
    天天写业务代码,我给撸了一个业务处理框架
    哪些场景会产生OOM?
    什么是final修饰 使用final修饰类、方法、变量的区别?
    通过tushare接口完成股票的实际交易的方法有哪些?
  • 原文地址:https://blog.csdn.net/weixin_51529433/article/details/126050961