leetcode--接雨水(双指针法,动态规划,单调栈)

 

目录

方法一:双指针法

 方法二:动态规划

方法三:单调栈




42. 接雨水 - 力扣(LeetCode)

 

黑色的是柱子,蓝色的是雨水,我们先来观察一下雨水的分布情况:
雨水落在凹槽之间,在一个凹槽的左右都会有两个柱子,两个柱子高度可能相同也可能不同,柱子的高低决定了凹槽的雨水的高度,雨水的高度等于两个柱子较低的高度。

方法一:双指针法

时间复杂度:O(N^2);

空间复杂度:O(1);

缺点:会超时;

思想:统计各个所在位置的左边最高高度和右边最高位置(第一个和最后一个柱子所在位置不用统计,他们不可能会接收雨水),然后算出各个位置雨水面积(两边的最高高度的较小值 - 当前位置的柱子的面积),最后将各个位置的面积相加得到总面积。

 具体实现:

class Solution {
public:
    int trap(vector<int>& height) {
        //面积和
        int sum = 0;
        for(int i = 0; i < height.size(); i++)
        {
            //第一个和最后一个不用统计
            if(i == 0 || i == height.size() - 1)
            continue;
            int maxLeft = height[i];
            int maxRight = height[i];
            //统计右边
            for(int j = i + 1; j < height.size(); j++)
            {
                maxRight = max(maxRight,height[j]);
            }
            //统计左边
            for(int j = i - 1; j >= 0; j--)
            {
                maxLeft = max(maxLeft,height[j]);
            }
            //高度计算
            int h = min(maxLeft,maxRight) - height[i];
            if(h > 0)
            sum += h;
        }
        return sum;
    }
};

 方法二:动态规划

时间复杂度为 O(N);

空间复杂度为 O(N);

思路:在方法一的基础上我们知道,只要知道各个位置的左右最高高度,通过计算就可以求得各个位置的面积,再相加就可以得到总面积。所以就需要遍历数组来找到左右最高高度,方法一使用双指针来求左右最高高度,每走到柱子位置就向左右方向进行统计,实际上是进行了重复计算的,导致时间复杂度为O(N^2)。因为柱子的位置都不会变,对于每个柱子,相对的左右最高高度也是不会变的,所以只需要遍历两次,把每个位置的左右最高高度计算出来放在两个数组中,最后再计算面积就行了。

class Solution {
public:
    int trap(vector<int>& height) {
        //动态规划做法
        //小于等于2个直接返回
        if(height.size() <= 2)
        return 0;
        //左边最高高度--数组初始化为0
        vector<int> maxLeft(height.size(),0);
        //右边最高高度--数组初始化为0
        vector<int> maxRight(height.size(),0);
        //遍历一次数组记录各个位置的左边最高高度
        maxLeft[0] = height[0];
        for(int i = 1; i < maxLeft.size(); i++)
        {
            maxLeft[i] = max(height[i],maxLeft[i - 1]);
        }
        //遍历一次数组记录各个位置的右边最高高度
        maxRight[maxRight.size() - 1] = height[height.size() - 1];
        for(int i = maxRight.size() - 2; i >= 0; i--)
        {
            maxRight[i] = max(height[i],maxRight[i + 1]);
        }
        //求和
        int sum = 0;
        for(int i = 0; i < height.size(); i++)
        {
            int count = min(maxLeft[i],maxRight[i]) - height[i];
            if(count > 0)
            {
                sum += count;
            }
        }
        return sum;
    }
};

方法三:单调栈

空间复杂度:O(n);

时间复杂度:O(n);

使用单调栈使站内元素有序,然而单调栈没有现成的容器,所以需要我们自己维持元素有序;

那么栈内有序是(栈底->栈顶) 小->大 还是 大->小呢?答案是大->小;当下一个柱子高度小于栈顶元素时就入栈,就能维持栈内有序,当遇到下一个柱子高度大于栈顶元素时就将栈顶pop掉,再将当前的栈顶元素与下一个柱子的高度比较就可以得到较小值,然后就和上面一样计算面积了。

class Solution {
public:
    int trap(vector<int>& height) {
        //如果数组个数两个及以下,直接return
        if(height.size() <= 2)
        return 0;
        //创建单调栈(栈顶->栈底==小->大),存放下标值
        stack<int> st;
        st.push(0);
        //统计面积
        int sum = 0;
        //行方向计算
        for(int i = 1; i < height.size(); i++)
        {
            //1.下一个元素小于栈顶元素
            if(height[i] < height[st.top()])
            {
                st.push(i);
            }
            //2.下一个元素等于栈顶元素--pop栈顶元素的下标,push下一个元素的下标
            else if(height[i] == height[st.top()])
            {
                st.pop();
                st.push(i);
            }
            //3.下一个元素大于栈顶元素--形成凹槽接收雨水,计算雨水面积
            else
            {
                while(!st.empty() && height[i] > height[st.top()])
                {
                    //中间的凹槽下标
                    int mid = st.top();
                    st.pop();
                    if(!st.empty())
                    {
                        //高度计算
                        int h = min(height[st.top()],height[i]) - height[mid];
                        //宽度计算
                        int w = i - st.top() - 1;
                        //面积
                        sum += h * w;
                    }
                }
                st.push(i);
            }
        }
        return sum;
    }
};

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/420245.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端Vue3项目如何打包成Docker镜像运行

将前端Vue3项目打包成Docker镜像并运行包括几个主要步骤&#xff1a;项目打包、编写Dockerfile、构建镜像和运行容器。下面是一个基本的流程&#xff1a; 1. 项目打包 首先&#xff0c;确保你的Vue3项目可以正常运行和打包。在项目根目录下执行以下命令来打包你的Vue3项目&am…

《PyTorch深度学习实践》第十三讲RNN进阶

一、 双向循环神经网络&#xff08;Bidirectional Recurrent Neural Network&#xff0c;BiRNN&#xff09;是一种常见的循环神经网络结构。与传统的循环神经网络只考虑历史时刻的信息不同&#xff0c;双向循环神经网络不仅考虑历史时刻的信息&#xff0c;还考虑未来时刻的信息…

14:00面试,14:07就出来了,问的问题过于变态了。。。

我从一家小公司转投到另一家公司&#xff0c;期待着新的工作环境和机会。然而&#xff0c;新公司的加班文化让我有些始料未及。虽然薪资相对较高&#xff0c;但长时间的工作和缺乏休息使我身心俱疲。 就在我逐渐适应这种高强度的工作节奏时&#xff0c;公司突然宣布了一则令人…

Leetcode : 数组拆分 I

给定长度为 2n 的整数数组 nums &#xff0c;你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), ..., (an, bn) &#xff0c;使得从 1 到 n 的 min(ai, bi) 总和最大。返回该 最大总和 。 思路&#xff1a;2n长度数组&#xff0c;共有n对&#xff0c;原有思路暴力破解法…

centos7安装jdk8、maven3.9

jdk8安装 下载安装包 下载安装包地址 下载的时候需要注册oracle账号&#xff0c;没有的可以使用现成的 账号&#xff1a;2028056560qq.com 密码&#xff1a;Oracle1234 放到指定的目录 解压 tar -xvzf jdk-8u401-linux-i586.tar.gz 配置环境变量 添加JAVA_HOME变量 vim…

Linux之gcc和makefile的使用详细解析

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言进阶 数据结构初阶 Linux C初阶 算法 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力&#xff0c;一起奔赴大厂 目录 一.gcc/g安装 二.gcc运行代码 三.gcc是如何完成的 3.1预处…

【Leetcode每日一刷】贪心算法|122.买卖股票的最佳时机 II、55. 跳跃游戏

一、122.买卖股票的最佳时机 II 力扣题目链接 &#x1f984;解题思路&#xff1a; 首先需要明确的几个点&#xff1a; 当前只能有最大一支股票每一天操作只能3选1&#xff1a;买or卖or休息 此外&#xff0c;对于贪心&#xff0c;总有像下面图示的一种直觉&#xff1a;如果…

11.盛最多水的容器

题目&#xff1a;给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 解题思路&#xff1a;可以…

算法打卡day5|哈希表篇01|Leetcode 242.有效的字母异位词 、19.删除链表的倒数第N个节点、202. 快乐数、1. 两数之和

哈希表基础知识 哈希表 哈希表关键码就是数组的索引下标&#xff0c;然后通过下标直接访问数组中的元素&#xff1b;数组就是哈希表的一种 一般哈希表都是用来快速判断一个元素是否出现集合里。例如要查询一个名字是否在班级里&#xff1a; 要枚举的话时间复杂度是O(n)&…

【开源】JAVA+Vue.js实现天沐瑜伽馆管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 瑜伽课程模块2.3 课程预约模块2.4 系统公告模块2.5 课程评价模块2.6 瑜伽器械模块 三、系统设计3.1 实体类设计3.1.1 瑜伽课程3.1.2 瑜伽课程预约3.1.3 系统公告3.1.4 瑜伽课程评价 3.2 数据库设计3.2.…

【C语言】动态内存管理常用函数

前言 我们在之前学习的数组开辟的空间是固定不变的&#xff0c;有时候我们需要的空间⼤⼩在程序运⾏的时候才能知道~ c语言中的动态内存开辟&#xff0c;让程序员⾃⼰可以根据实际需求申请和释放相应空间&#xff0c;这使得空间的开辟变得灵活了许多。 欢迎关注个人主页&#x…

【C++进阶】哈希表的闭散列和开散列(哈希桶)的代码实现

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

mariadb数据库——安装,创建数据库

MariaDB是一个流行的开源关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它是MySQL的一个分支。 安装 apt -y install mariadb-servervi /etc/mysql/mariadb.conf.d/50-server.cnf character-set-server utf8mb4 collation-server utf8mb4_general_c…

什么时候要用到Reflect API?

参考文档 https://www.zhihu.com/question/460133198 https://cn.vuejs.org/guide/extras/reactivity-in-depth.html https://juejin.cn/post/7103764386220769311 Reflect API 一般搭配 Proxy API 一起使用。什么是 Proxy API 呢&#xff1f; 先回顾下 vue 的数据响应性是如何…

【已解决】卸载软件时显示“无法使用此产品的安装源,请确认安装源存在,并且你可以访问它”报错截图如下

卸载软件时显示“无法使用此产品的安装源&#xff0c;请确认安装源存在&#xff0c;并且你可以访问它”报错截图如下 使用Uninstall Tool软件强制删除&#xff0c;绕过软件自带的uninstall程序。&#xff08;小白推荐&#xff0c;如下图&#xff09; Uninstall Tool - Unique…

【DAY06 软考中级备考笔记】数据结构:树

数据结构&#xff1a;树 3月1日 – 天气&#xff1a;晴 之前在B站看的视频讲的是在太过简单&#xff0c;弃了。现在换了新的视频继续&#xff0c;后续会重新看前面的视频补过来。https://www.bilibili.com/video/BV1pT4m1S7uH/ 1. 树的基本概念 需要注意的是&#xff1a; 并不是…

代码随想录算法训练营第五天

● 自己看到题目的第一想法 242. 有效的字母异位词 方法&#xff1a; 方法一&#xff1a; 暴力法 1. 分别对s, t排序 2. 遍历s与t 判断s[i]!t[i] 返回 false 否则 返回true思路&#xff1a; 注意&#xff1a; 代码&#xff1a; bool cmp(char a, char b){return a<b;…

解决GitHub无法访问的问题:手动修改hosts文件与使用SwitchHosts工具

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua&#xff0c;在这里我会分享我的知识和经验。&#x…

Node.js+Express后端,自定义接口

6分钟学会Express 后端 API 开发 Node.js 2020最新版_哔哩哔哩_bilibili 要使用Node.js和Express搭建一个简单的后台服务器&#xff0c;用于接收带有token的请求头&#xff0c;你可以按照以下步骤进行操作&#xff1a; 首先&#xff0c;确保你已经安装了Node.js和npm&#xff0…

OpenAI员工自曝996作息表,网友:真正的卷不需要强迫

鱼羊 发自 凹非寺 量子位 | 公众号 QbitAI OpenAI也996&#xff0c;实锤了&#xff08;doge&#xff09;。 思维链作者、从谷歌跳槽OpenAI的Jason Wei刚刚分享了自己在OpenAI的一天&#xff1a; [9:00am] 起床 [9:30am] 搭乘Waymo前往Mission SF&#xff0c;途中在Tartine买…