leetcode 42 接雨水

简介: leetcode 42 接雨水

接雨水

9d4fea0391e344dcb426f3de585e70d5.png

双指针(超时)

class Solution {
public:
    int trap(vector<int>& height) {
        int left,right,result=0;
        for(int i=1 ; i<height.size()-1 ;i++)
        {
            left = height[i];
            right = height[i];
      //找到左右最高点
            for(int j=i+1 ; j<height.size();j++)
                if(height[j] > right) right = height[j];
            for(int j=i-1; j>=0 ;j--)
                if(height[j] > left) left = height[j];
            //计算当点的雨水,累加
            result = result + min(left,right) - height[i];
        }
        return result;
    }
};


单调栈


8d10fe8738504eeaaedc40df8a0ffbfb.png


从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。

因为一旦发现添加的柱子高度大于栈头元素了,此时就出现凹槽了,栈头元素就是凹槽底部的柱子,栈头第二个元素就是凹槽左边的柱子,而添加的元素就是凹槽右边的柱子。


d6e4f50e74964d478a8e236c54d0e289.png

遇到相同的元素,更新栈内下标,就是将栈里元素(旧下标)弹出,将新元素(新下标)加入栈中。

例如 5 5 1 3 这种情况。如果添加第二个5的时候就应该将第一个5的下标弹出,把第二个5添加到栈中。

因为我们要求宽度的时候 如果遇到相同高度的柱子,需要使用最右边的柱子来计算宽度。

8759e87f81fc4908bfffe67bfced99fd.png


单调栈处理逻辑

  • 先将下标0的柱子加入到栈中
  • 然后开始从下标1开始遍历所有的柱子
  • 如果当前遍历的元素(柱子)高度小于栈顶元素的高度,就把这个元素加入栈中,因为栈里本来就要保持从小到大的顺序(从栈头到栈底)。
  • 如果当前遍历的元素(柱子)高度等于栈顶元素的高度,要跟更新栈顶元素,因为遇到相相同高度的柱子,需要使用最右边的柱子来计算宽度。
  • 如果当前遍历的元素(柱子)高度大于栈顶元素的高度,此时就出现凹槽了,如图所示:栈顶和栈顶的下一个元素以及要入栈的三个元素来接水!

cfb13601cf514dabb0a1027d393d423c.png

class Solution {
public:
    int trap(vector<int>& height) {
        if(height.size()<=2) return 0;
        stack<int> st;
        int result = 0;
        st.push(0);
        for(int i=1 ; i<height.size() ;i++)
        {
          //当前柱子比栈顶的小
            if(height[i] < height[st.top()])
                st.push(i);
            //当前柱子和栈顶相等
            else if(height[i] == height[st.top()])
            {
                st.pop();
                st.push(i);
            //当前柱子比栈顶的大,产生了凹陷
            }else if(height[i] > height[st.top()])
            {
                while(st.empty()==0 && height[i] > height[st.top()])
                {
                    int mid = st.top();
                    st.pop();
                    if(st.empty()==0) 
                    {
                        int left = st.top();
                        int right = i;
                        int h = min(height[left] , height[right]) - height[mid];
                        int w = right - left -1;
                        result += h*w;
                    }
                }
                st.push(i);
            }
        }
        return result;
    }
};

二刷(双指针超时)

class Solution {
public:
    int trap(vector<int>& height) {
        int result = 0;
        for(int i=1; i<height.size()-1 ;i++)
        {
            int left = i;
            int right = i;
            for(int j=left ; j>=0 ; j--)
                if(height[j] > height[left]) left = j;
            for(int j=right ; j<height.size() ; j++)
                if(height[j] > height[right]) right = j;
            if(left != i && right != i)
            {
                result += min(height[left] , height[right]) - height[i];
            }      
        }
        return result;
    }
};

二刷(总面积 - 柱子面积 = 水面积)

class Solution {
public:
    int trap(vector<int>& height) {
        int sum = 0;
        int rel = 0;
        int max_h = 0;
        int tmp_h;
        for(int i = 0 ; i<height.size() ;i++)
            if(height[i] > height[max_h]) max_h = i; //计算最高点
        tmp_h = 0;
        for(int i = 0 ; i<max_h ;i++) //从左往最高点算
        {
            if(height[i] >= height[tmp_h]) tmp_h = i;
            sum += height[tmp_h];
            rel += height[i];
        }
        tmp_h = height.size()-1;
        for(int i = height.size()-1 ; i > max_h ;i--)//从右往最高的算
        {
            if(height[i] >= height[tmp_h]) tmp_h = i;
            sum += height[tmp_h];
            rel += height[i];
        }
        return sum - rel; //总面积 - 真实柱子面积 = 水面积
    }
};

二刷(单调栈)

class Solution {
public:
    int trap(vector<int>& height) {
        stack<int> my_stack;
        int result = 0;
        my_stack.push(0);
        for(int i=1 ; i<height.size() ; i++)
        {
            if(height[i] < height[my_stack.top()])
                my_stack.push(i);
            else if(height[i] == height[my_stack.top()])
            {
                my_stack.pop();
                my_stack.push(i);
            }else if(height[i] > height[my_stack.top()])
            {
                while(my_stack.size() != 0 && height[i] > height[my_stack.top()] )
                {
                    int mid = my_stack.top();
                    my_stack.pop();
                    if(my_stack.size() != 0)
                    {
                        int left = my_stack.top();
                        int right = i;
                        result += (right - left - 1) * ( min( height[left] , height[right]) - height[mid] );
                    }
                }
                my_stack.push(i);
            }
        }   
        return result;
    }
};
相关文章
|
10月前
|
人工智能 算法 NoSQL
LRU算法的Java实现
LRU(Least Recently Used)算法用于淘汰最近最少使用的数据,常应用于内存管理策略中。在Redis中,通过`maxmemory-policy`配置实现不同淘汰策略,如`allkeys-lru`和`volatile-lru`等,采用采样方式近似LRU以优化性能。Java中可通过`LinkedHashMap`轻松实现LRUCache,利用其`accessOrder`特性和`removeEldestEntry`方法完成缓存淘汰逻辑,代码简洁高效。
482 0
|
存储 关系型数据库 物联网
【PolarDB开源】PolarDB在物联网(IoT)数据存储中的应用探索
【5月更文挑战第27天】PolarDB,阿里云的高性能云数据库,针对物联网(IoT)数据存储的挑战,如大规模数据、实时性及多样性,展现出高扩展性、高性能和高可靠性。它采用分布式架构,支持动态扩展,保证99.95%的高可用性,并能处理结构化、半结构化和非结构化数据。通过SDK实现数据实时写入,支持SQL查询和冷热数据分层,有效降低成本。随着IoT发展,PolarDB在该领域的应用将更加广泛。
508 1
|
存储 分布式计算 监控
Hadoop在云计算环境下的部署策略
【8月更文第28天】Hadoop是一个开源软件框架,用于分布式存储和处理大规模数据集。随着云计算技术的发展,越来越多的企业开始利用云平台的优势来部署Hadoop集群,以实现更高的可扩展性、可用性和成本效益。本文将探讨如何在公有云、私有云及混合云环境下部署和管理Hadoop集群,并提供具体的部署策略和代码示例。
796 0
|
存储 机器学习/深度学习 算法
数据结构和算法学习记录——空间复杂度的计算(冒泡排序、阶乘递归、斐波那契数列递归、常见复杂度对比、栈帧、栈溢出)
数据结构和算法学习记录——空间复杂度的计算(冒泡排序、阶乘递归、斐波那契数列递归、常见复杂度对比、栈帧、栈溢出)
533 0
|
算法 C语言
【数据结构】快速排序(4种方式实现)
【数据结构】快速排序(4种方式实现)
588 1
|
JavaScript Linux 数据安全/隐私保护
如何在CentOS7部署Wiki.js知识库并实现分享好友公网远程使用【内网穿透】
如何在CentOS7部署Wiki.js知识库并实现分享好友公网远程使用【内网穿透】
|
JavaScript Java Docker
使用 Dockerfile 构建和定制 Docker 镜像
Dockerfile是构建Docker镜像的文本文件,包含一系列指令,如`FROM`, `WORKDIR`, `COPY`, `RUN`, `EXPOSE`和`CMD`。它用于自动化`docker build`命令来创建Image。使用Dockerfile可以基于官方镜像定制应用镜像,方便应用容器化和扩展。基本流程包括选择基础镜像、设置工作目录、安装依赖、暴露端口和定义启动命令。构建镜像使用`docker build`,运行容器用`docker run`。了解并熟练使用Dockerfile能提升容器化部署效率。
|
测试技术 双11 缓存
独家揭秘 | 阿里怎么做双11全链路压测?
本文是《Performance Test Together》(简称PTT)系列专题分享的第7期,该专题将从性能压测的设计、实现、执行、监控、问题定位和分析、应用场景等多个纬度对性能压测的全过程进行拆解,以帮助大家构建完整的性能压测的理论体系,并提供有例可依的实战。
8036 100

热门文章

最新文章