【59天|503.下一个更大元素II ● 42. 接雨水】

news2024/12/22 23:29:24

503.下一个更大元素II

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        stack<int> st;
        int n = nums.size();
        vector<int> res (n, -1);
        for(int i=0; i<2*n;i++)
        {
            while(!st.empty()&&nums[i%n]>nums[st.top()]){
                res[st.top()] = nums[i%n];
                st.pop();
            }
            st.push(i%n);
        }
        return res;
    }
};

42. 接雨水

在这里插入图片描述
height = [0,1,0,2,1,0,1,3,2,1,2,1]

假设我们遍历数组height, 那么以height[i] 为底可以接的雨水为多少呢?
这里我们可以推出一个很重要的公式: sum[i] = min(height[i]左边最高的边,height[i]右边最高的边) - height[i];(sum[i] 表示height第i个元素可以接到的雨水)

例如: height[2] = 0; 左边的最大元素等于 1, 右边最大元素等于3. 求得height[2] 位置可以接的雨水为 min(1,3) -0 = 1;

1. 暴力法

按照上面的分析, 我们只需要遍历height, 然后求height[i] 左边的最大元素lmax和右边的最大元素rmax

然后就可以按上面的公式计算出 height[i]可接住的雨水。最后用一个变量记录下这整个过程接的雨水就行。不难写出如下代码:

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 rmax = height[i]; // 记录右边柱子的最高高度
            int lmax = height[i]; // 记录左边柱子的最高高度
            for (int r = i + 1; r < height.size(); r++) {
            //从当前位置向右遍历,找到height[i] 的rHeight
                if (height[r] > rmax) rmax = height[r];
            }
            for (int l = i - 1; l >= 0; l--) {
            //从当前位置向左遍历,找到height[i] 的lHeight
                if (height[l] > lmax) lmax = height[l];
            }
            //按照公式计算height[i]接的雨水
            int h = min(lHeight, rHeight) - height[i];
            if (h > 0) sum += h;
        }
        return sum;
    }
};

时间复杂度o(n2), 空间复杂度O(1)。暴力的解法太费事,在leetcode是无法通过的。继续思考一下!

2. 动态规划

上述代码主要是在求 rmaxlmax时花了太多时间。 我们可以考虑用一个额外空间记录每一个元素的 rmax, lmax。 然后在求雨水时到这里面取对应元素的 rmaxlmax即可。

求每个元素的rmaxlmax我们可以用动规的方法。
不难发现 lmax 满足如下规律:

lmax[i] = max(lmax[i-1], height[i]);  //(height.size()-1>i>0)
lmax[i] = 0; // i=0;

所以可以写出如下代码:

vector<int> lmax(height.size(), 0);
lmax[0] = height[0];
for (int i = 1; i < size; i++) {
	lmax[i] = max(height[i], lmax[i - 1]);
}

同理, 可求rmax数组。

rmax[size - 1] = height[size - 1];
for (int i = size - 2; i >= 0; i--) {
    rmax[i] = max(height[i], rmax[i + 1]);
}

最终整体代码为:

class Solution {
public:
    int trap(vector<int>& height) {
        if (height.size() <= 2) return 0;
        vector<int> lmax(height.size(), 0);
        vector<int> rmax(height.size(), 0);
        int size = height.size();

        // 记录每个柱子左边柱子最大高度
        lmax[0] = height[0];
        for (int i = 1; i < size; i++) {
            lmax[i] = max(height[i], lmax[i - 1]);
        }
        // 记录每个柱子右边柱子最大高度
        rmax[size - 1] = height[size - 1];
        for (int i = size - 2; i >= 0; i--) {
            rmax[i] = max(height[i], rmax[i + 1]);
        }
        // 求和
        int sum = 0;
        for (int i = 0; i < size; i++) {
            int count = min(lmax[i], rmax[i]) - height[i];
            if (count > 0) sum += count;
        }
        return sum;
    }
};

我们发现时间复杂度减低为O(n), 但是空间复杂度增大到O(n).这样写是可以通过这题的.
在这里插入图片描述

3. 双指针

我们进一步优化一下, 考虑如何不要额外空间去解决这题.

我们回到题目一开始时,我们推出的那个重要公式:
sum[i] = min(lmax[i], rmax[i]) - height[i];

从这个公式可以知道,如果想求sum[i] 那么必须得知道lmax[i]rmax[i]
其中, lmax[i] 其实可以在从左到右遍历height得过程中, 通过动规一样的思路求得.

lmax = max(height[left], lmax);

rmax[i] 由于height[i] 右边的元素都还是遍历到,所以是不可能求到的.

那么我们思考一下, 我们不知道rmax[i]等于多少, 但是如果能保证rmax[i] >= lmax[i] 是不是也能求出sum[i]? 此时, sum[i] = lmax[i]-height[i];

于是, 我们尝试从rmax[i]的动规规律中找到能保证rmax[i] >= lmax[i]的条件:

rmax[i] = max(height[i], rmax[i + 1]);// 已知的动规规律, rmax[i] >= rmax[i+1] >= .... >= rmax[height.size()-1];, rmax[i] >= rmax[j] // j>i

同理可得, lmax[j] >= lmax[i] // j>i

如果想让rmax[i] >= lmax[i], 由于rmax[i] >= rmax[j] ,
所以当rmax[j] > lmax[i]时, 就能保证rmax[i] >= lmax[i]. 此时 sum[i] = lmax[i]-height[i];

那么当rmax[j]<= lmax[i]时是什么情况呢?
由于lmax[j] >= lmax[i], 那么 lmax[j]>=rmax[j] 恒成立. 有 sum[j] = rmax[j]-height[i];

综上, 若rmax[j] > lmax[i], sum[i] = lmax[i]-height[i];
rmax[j]<= lmax[i], sum[j] = rmax[j]-height[i];

画个图加深理解:

在这里插入图片描述

分析到这一步其实很明显了,这就是首尾指针的题.

如果首指针的lmax < 尾指针的rmax, 那么sum[i] = lmax-height[i], 然后首指针右移;
否则首指针的lmax >= 尾指针的rmax, 即尾指针的rmax<=首指针的lmax, 那么sum[j] = rmax - height[i], 然后尾指针左移.
重复这个过程, 直到首尾指针相遇.

class Solution {
public:
    int trap(vector<int>& height) {
        int left = 0, right = height.size()-1;
        int left_lmax = 0, right_rmax = 0;
        int res =0;
        while(left<right)
        {   
            left_lmax = max(height[left], left_lmax);
            right_rmax = max(height[right], right_rmax);
            if(left_lmax<right_rmax)
            {
                res += left_lmax - height[left];
                left++;
            }
            else{//right_rmax <= left_lmax
                res += right_rmax - height[right];
                right--;
            }
        }
        return res;
    }
};

时间复杂度O(n), 空间复杂度O(1)
空间复杂度o(1)\ 时间复杂度o(n)

4. 单调栈

单调栈求雨水的思路和公式跟上面提到的三种方法不一样.单调栈的解法可以看卡哥的单调栈.

class Solution {
public:
    int trap(vector<int>& height) {
        stack<int> st;
        st.push(0);
        int sum = 0;
        for (int i = 1; i < height.size(); i++) {
            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;
    }
};

时间复杂度O(n), 空间复杂度O(n)
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第13章_事务基础知识

第13章_事务基础知识 1.数据库事务概述 事务是数据库区别于文件系统的重要特性之一&#xff0c;当我们有了事务就会让数据库始终保持一致性&#xff0c;同时我们还能通过事务的机制恢复到某个时间点&#xff0c;这样可以保证已提交到数据库的修改不会因为系统崩溃而丢失。 1…

Moonbeam路由流动性

Moonbeam路由流动性&#xff08;Moonbeam Routed Liquidity, MRL&#xff09;使加密资产流动性能够从其他生态系统&#xff08;如以太坊、Solana、Polygon或Avalanche&#xff09;进入波卡生态系统。借助MRL&#xff0c;用户可以通过简洁的用户体验向/从波卡转移他们的流动性。…

横竖屏切换导致页面频繁重启?详细解读screenLayout

目录 前言configChangesscreenLayout平板问题总结 前言 前几天多名用户反馈同一个问题&#xff0c;在小新平板上无法上网课&#xff0c;点击上课按钮后就退回到首页了。了解了一下发现小新平板现在销量特别好&#xff0c;于是赶紧申请了一台测试机打算看看到底是什么问题。 最…

牛客网语法篇刷题(C语言) — 分支控制

作者主页&#xff1a;paper jie的博客_CSDN博客-C语言,算法详解领域博主 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文录入于《C语言-语法篇》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白…

附录6-todolist案例

效果是这样的 可以添加新任务&#xff0c;改变任务状态&#xff0c;与筛选任务列表 使用vant创建的项目 使用到了bootstrap&#xff0c;首先 npm install bootstrap进行安装&#xff0c;安装后导入css与js 上中下是三个组件&#xff0c;依次是 todo_input&#xff0c;todo_li…

Python控制LitePoint IQxel-MW 无线网络测试仪

前言 由于项目需要进行WIFI和BT&#xff08;蓝牙&#xff09;的射频测试&#xff0c;所以需要开发一款支持WIFI/BT射频测试的工具。开发射频测试工具的话那肯定离不开仪表的控制。我们项目用的就Litepoint的IQxel-MW无线网络测试仪。这篇文章主要就是介绍一下如何控制仪表以及…

初探core组件:opencv - core组件进阶

core组件进阶 1.访问图像中的像素1.1 图像在内存之中的存储方式1.2 颜色空间缩减1.3 LUT函数&#xff1a;Look up table1.4 计时函数 2. ROI区域图像叠加&图像混合2.1 感兴趣区域&#xff1a;ROI2.2 ROI案例2.2 线性混合操作2.3 计算数组加权和&#xff1a;addWeighted()函…

python-segno:二维码制作

目录 二维码版本 微二维码、数据掩码、数据流、模式 微二维码 数据掩码 数据流 二维码模式 二维码背景 二维码参数 helpers方法 其他库制作及二维码读取&#xff1a;python生成和读取二维码_觅远的博客-CSDN博客 安装&#xff1a;pip install segno import segnoqr …

Qt+QtWebApp开发笔记(六):http服务器html实现静态相对路径调用第三方js文件

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/131244269 红胖子网络科技博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

经典30个嵌入式面试问题

经典30个嵌入式面试问题 嵌入式系统的面试经典问题有很多&#xff0c;以下是其中的30个常见问题&#xff1a; 1. 什么是嵌入式系统&#xff1f; 2. 嵌入式系统和普通计算机系统有什么区别&#xff1f; 3. 嵌入式系统的主要应用领域有哪些&#xff1f; 4. 嵌入式系统的设计…

接口测试工具之postman

概念 接口测试是什么&#xff1f; 百度百科给出的解释是&#xff1a; 接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间…

构造函数初始化列表的问题

构造函数初始化列表的问题 无法按照表达式中的算符来修改值原因基本原则由此引申的问题使用初始化列表对类成员初始化在构造函数中赋值对类成员初始化 针对构造函数传参,使用引用的情况使用初始化列表对类成员初始化在构造函数中赋值对类成员初始化 将属性也使用引用总结 无法按…

STM32开发——看门狗

目录 1.独立看门狗 1.1需求 1.2CubeMX设置 1.3函数代码 2.窗口看门狗 2.1需求 ​2.2WWDG配置&#xff1a; 2.3函数代码 3.独立看门狗和窗口看门狗的异同点 1.独立看门狗 监测单片机程序运行状态的模块或者芯片&#xff0c;俗称“看门狗”(watchdog) 。 独立看门狗本质 本…

6、DuiLib控件消息响应处理

文章目录 1、DuiLib控件消息响应处理2、基本的消息响应处理 Notify3、仿 MFC 形式消息响应 DUI_DECLARE_MESSAGE_MAP4、事件委托 MakeDelegate5、消息捕获&#xff08;拦截&#xff09;原生消息 HandleMessage 1、DuiLib控件消息响应处理 <?xml version"1.0" en…

软件测试基础教程学习3

文章目录 软件质量与测试3.1 软件质量问题的原因3.2 对软件质量特性的理解3.3 基于软件质量特性的测试3.4 软件能力成熟度模型&#xff08;CMM&#xff09; 软件质量与测试 3.1 软件质量问题的原因 软件质量问题的原因有以下几种&#xff1a; 软件本身的特点和目前普遍采用的…

AWTK实现汽车仪表Cluster/DashBoard嵌入式GUI开发(五):芯片型号

前言 随着汽车四化的推进,可以说汽车仪表也变成越来越智能化的一个ECU部件了。市面上的车型很多,油车发展了很多年,都有仪表,电车也发展起来了,车型也非常丰富,也都有仪表。仪表现在是作为多屏中一个屏存在的,现在车上最多的就是屏了,最大的要算中控屏了,有的还有空调…

【基础】MQTT -- MQTT 协议详解

【基础】MQTT -- MQTT协议详解 与 Broker 建立连接CONNECT 数据包CONNACK 数据包 断开连接DISCONNECT 数据包 订阅与发布PUBLISH 数据包SUBSCRIBE 数据包SUBACK 数据包UNSUBSCRIBE 数据包UNSUBACK 数据包 本文内容针对 MQTT 3.1.1 版本&#xff0c;从连接、发布与订阅等方面对协…

OpenCV做个熊猫表情

有的时候很想把一些有意思的图中的人脸做成熊猫表情&#xff0c;但是由于不太会ps&#xff0c;只能无奈放弃&#xff0c;so sad... 正好最近想了解下opencv的使用&#xff0c;那就先试试做个简单的熊猫表情生成器把~~ 思路就是&#xff0c;工具给两个参数&#xff0c;一个是人…

最小系统板STM32F103C8T6烧录程序指南

STM32F103C8T6烧录程序 【购买链接】&#xff1a;STM32F103C8T6最小系统板 方法一&#xff1a;使用SWD模式烧录 此时BOOT0 0&#xff0c;BOOT1 X&#xff08;任意&#xff09;&#xff0c;跳线帽接法如下图所示 接好后&#xff0c;若手边有STLINK的话&#xff0c;可以使用…

DAY25:二叉树(十五)修剪二叉搜索树+有序数组转换为二叉搜索树+二叉搜索树转化为累加树

文章目录 669.修剪二叉搜索树思路错误代码示例最开始的写法debug测试逻辑错误&#xff1a;需要两次递归的原因内存操作报错&#xff1a;操作了已经被删除的内存的指针&#xff08;力扣平台delete操作的问题&#xff0c;放IDE里就好了&#xff09;打日志debug示例 力扣平台delet…