代码随想录第58天

news2024/11/19 14:53:42

1.每日温度:

 1.什么时候用单调栈呢?

通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了

2.单调栈里元素是递增呢? 还是递减呢?

注意以下讲解中,顺序的描述为 从栈头到栈底的顺序,因为单纯的说从左到右或者从前到后,不说栈头朝哪个方向的话,大家一定比较懵。

这里我们要使用递增循序(再强调一下是指从栈头到栈底的顺序),因为只有递增的时候,栈里要加入一个元素i的时候,才知道栈顶元素在数组中右面第一个比栈顶元素大的元素是i。

即:如果求一个元素右边第一个更大元素,单调栈就是递增的,如果求一个元素右边第一个更小元素,单调栈就是递减的。

使用单调栈主要有三个判断条件。

  • 当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况
  • 当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况
  • 当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况

把这三种情况分析清楚了,也就理解透彻了

接下来我们用temperatures = [73, 74, 75, 71, 71, 72, 76, 73]为例来逐步分析,输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。


首先先将第一个遍历元素加入单调栈


加入T[1] = 74,因为T[1] > T[0](当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况)。

我们要保持一个递增单调栈(从栈头到栈底),所以将T[0]弹出,T[1]加入,此时result数组可以记录了,result[0] = 1,即T[0]右面第一个比T[0]大的元素是T[1]。


加入T[2],同理,T[1]弹出


加入T[3],T[3] < T[2] (当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况),加T[3]加入单调栈。


加入T[4],T[4] == T[3] (当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况),此时依然要加入栈,不用计算距离,因为我们要求的是右面第一个大于本元素的位置,而不是大于等于!


加入T[5],T[5] > T[4] (当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况),将T[4]弹出,同时计算距离,更新result 


T[4]弹出之后, T[5] > T[3] (当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况),将T[3]继续弹出,同时计算距离,更新result 


直到发现T[5]小于T[st.top()],终止弹出,将T[5]加入单调栈


加入T[6],同理,需要将栈里的T[5],T[2]弹出


同理,继续弹出


此时栈里只剩下了T[6]


加入T[7], T[7] < T[6] 直接入栈,这就是最后的情况,result数组也更新完了。

此时有同学可能就疑惑了,那result[6] , result[7]怎么没更新啊,元素也一直在栈里。

其实定义result数组的时候,就应该直接初始化为0,如果result没有更新,说明这个元素右面没有更大的了,也就是为0。

以上在图解的时候,已经把,这三种情况都做了详细的分析。

  • 情况一:当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况
  • 情况二:当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况

把遍历元素的下标放入栈中

  • 情况三:当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况

弹出栈顶元素下标直到为空或者出现情况1或2,记得把i放进去放进去。

这里注意放的是下标,不是元素,因为如果放的是元素出现错误:

 

这里answer[2]和answer[4]出现问题,关键是如果遍历元素小于等于栈头元素时放入元素后,出现大于栈头的元素,但是没有一次性弹完,等到出现遍历的元素比弹剩下的元素大的时候,他中间隔了好多元素,但是j从遍历的元素开始减,所以会出错,会使answer[弹剩下的元素的下标]没有结果,还有会使answer[某个元素的下标]第二次赋值。(看不懂看上面的图)

 

通过以上过程,大家可以自己再模拟一遍,就会发现:只有单调栈递增(从栈口到栈底顺序),就是求右边第一个比自己大的,单调栈递减的话,就是求右边第一个比自己小的。

C++代码如下:

// 版本一
class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& T) {
        // 递增栈
        stack<int> st;
        vector<int> result(T.size(), 0);
        st.push(0);
        for (int i = 1; i < T.size(); i++) {
            if (T[i] < T[st.top()]) {                       // 情况一
                st.push(i);
            } else if (T[i] == T[st.top()]) {               // 情况二
                st.push(i);
            } else {
                while (!st.empty() && T[i] > T[st.top()]) { // 情况三
                    result[st.top()] = i - st.top();
                    st.pop();
                }
                st.push(i);
            }
        }
        return result;
    }
};

建议一开始 都把每种情况分析好,不要上来看简短的代码,关键逻辑都被隐藏了

精简代码如下:

// 版本二
class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& T) {
        stack<int> st; // 递增栈
        vector<int> result(T.size(), 0);
        for (int i = 0; i < T.size(); i++) {
            while (!st.empty() && T[i] > T[st.top()]) { // 注意栈不能为空
                result[st.top()] = i - st.top();
                st.pop();
            }
            st.push(i);

        }
        return result;
    }
};

2.下一个更大的元素:
淦,第一眼题目什么意思都不知道,还是看例题解析看懂的,大概意思就是answer[i]是num1[i]在num2中(就是在num2中num2[j]==num1[i]的位置)右边的第一个比他大的数,如果没找到就是-1。

然后题解的思路是找num2中每一个元素右边第一大的数,然后如果他是在num1中出现过,那就把他记录在result中。

【C++】map.count和map.find

以上分析完毕,C++代码如下:(其实本题代码和 739. 每日温度 (opens new window)是基本差不多的)

// 版本一
class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        stack<int> st;
        vector<int> result(nums1.size(), -1);
        if (nums1.size() == 0) return result;

        unordered_map<int, int> umap; // key:下标元素,value:下标
        for (int i = 0; i < nums1.size(); i++) {
            umap[nums1[i]] = i;
        }
        st.push(0);
        for (int i = 1; i < nums2.size(); i++) {
            if (nums2[i] < nums2[st.top()]) {           // 情况一
                st.push(i);
            } else if (nums2[i] == nums2[st.top()]) {   // 情况二
                st.push(i);
            } else {                                    // 情况三
                while (!st.empty() && nums2[i] > nums2[st.top()]) {
                    if (umap.count(nums2[st.top()]) > 0) { // 看map里是否存在这个元素
                        int index = umap[nums2[st.top()]]; // 根据map找到nums2[st.top()] 在 nums1中的下标
                        result[index] = nums2[i];
                    }
                    st.pop();
                }
                st.push(i);
            }
        }
        return result;
    }
};

针对版本一,进行代码精简后,代码如下:

// 版本二
class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        stack<int> st;
        vector<int> result(nums1.size(), -1);
        if (nums1.size() == 0) return result;

        unordered_map<int, int> umap; // key:下标元素,value:下标
        for (int i = 0; i < nums1.size(); i++) {
            umap[nums1[i]] = i;
        }
        st.push(0);
        for (int i = 1; i < nums2.size(); i++) {
            while (!st.empty() && nums2[i] > nums2[st.top()]) {
                if (umap.count(nums2[st.top()]) > 0) { // 看map里是否存在这个元素
                    int index = umap[nums2[st.top()]]; // 根据map找到nums2[st.top()] 在 nums1中的下标
                    result[index] = nums2[i];
                }
                st.pop();
            }
            st.push(i);
        }
        return result;
    }
};

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

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

相关文章

阿里云服务器解析绑定后访问不了的变态策略

阿里云服务器默认把80端口毙掉了&#xff0c;说是为了服务器安全。 客户买个一般服务器不就是弄个网站&#xff0c;80或者443端口默认还需要自己打开。 好比买个车&#xff0c;为了安全&#xff0c;没有轮胎&#xff0c;怕客户跑起来撞人&#xff0c;买完车让客户自己安装轮胎。…

Redis常见问题、各个分布式锁优缺点-05

Redis集群为什么至少需要三个master节点&#xff0c;并且推荐节点数为奇数&#xff1f; 因为新master的选举需要大于半数的集群master节点同意才能选举成功&#xff0c;如果只有两个master节点&#xff0c;当其中一个挂了&#xff0c;是达不到选举新master的条件的。 奇数个ma…

BLIP和BLIP2

文章主要是对BLIP2 &#xff08;使用冻结图像编码器和大型语言模型的Bootstrapping语言图像预训练&#xff09;论文的阅读笔记&#xff0c;也对BLIP&#xff08;用于统一视觉语言理解和生成的Bootstrapping语言图像预训练&#xff09;算法进行了简单的介绍。 一、BLIP&#xf…

走进人工智能| Computer Vision 数字化时代的视觉启示录

前言&#xff1a; 计算机视觉是通过模仿人类视觉系统的工作原理&#xff0c;使计算机能够感知、理解和解释图像和视频的能力。 文章目录 序言背景适用领域技术支持应用领域程序员如何学总结 序言 计算机视觉是人工智能领域的一个重要分支&#xff0c;它涉及使计算机能够“看”…

nginx的开始(一)---nginx的安装

文章目录 1.nginx是什么&#xff1f;2.nginx安装2.1.安装准备&#xff1a;2.2.进行安装&#xff1a;2.2.1.apt安装&#xff08;快速&#xff09;2.2.2.源码安装 2.3.配置文件简解&#xff08;nginx.conf&#xff09; 1.nginx是什么&#xff1f; Nginx&#xff08;发音为"e…

AndroidT(13) init 进程 -- first stage init 的初始化 (二)

1.概览 第一阶段的 init 工作主要用于读取系统启动阶段需要的配置信息(例如 linux的bootconfig&#xff0c;cmdline等配置信息&#xff09;、挂载文件系统、安装 kernel 中的模块驱动&#xff0c;最后就是启动第二阶段的 init 来进行 Android 系统相关的组件。第一阶段的 init …

《微服务实战》 第三十章 分布式事务框架seata TCC模式

前言 本章节介绍分布式事务框架seata TCC模式&#xff0c;上一章节介绍seata以及集成到Springboot、微服务框架里。 1、TCC模式 一个分布式的全局事务&#xff0c;整体是 两阶段提交 的模型。全局事务是由若干分支事务组成的&#xff0c;分支事务要满足 两阶段提交 的模型要…

如何利用ChatGPT写毕业论文

如何利用ChatGPT写毕业论文 ChatGPT是什么&#xff1f;利用ChatGPT写毕业论文的步骤1.准备数据2.训练模型3.生成论文4.检查论文 总结地址 ChatGPT是什么&#xff1f; ChatGPT是一个基于GPT-2模型的开源聊天机器人&#xff0c;它可以回答用户的问题&#xff0c;进行闲聊和提供各…

或许是一个新的算法方向?

动动发财的小手&#xff0c;点个赞吧&#xff01; 今日谷歌 DeepMind 使用深度强化学习发现更快的排序算法&#xff0c;相关论文[1]成果已经发表在Nature上。 据报道&#xff1a;该算法可以提速 70&#xff05;&#xff0c;相比之下&#xff0c;快了3倍之多。 摘要 排序或散列等…

230611-通过Doxygen实现项目代码的文档自动化生成(Mac+Win通用)

背景介绍 目前主流的Python项目的文档管理多通过Sphinx实现&#xff1b;当前Sphinx尚未有针对C#等代码的插件&#xff1b;若想对C#的项目代码进行Sphinx的管理&#xff0c;可通过Doxygen导出为xml文件&#xff0c;进行二次转换&#xff1b;有关Doxygen的介绍及使用&#xff0c…

Java使用Opencv进行大图找小图并使用其找图功能进行bilibili视频下载案例

Java使用Opencv进行大图找小图并使用其找图功能进行bilibili视频下载案例 一、Opencv大图找小图说明二、Opencv的window安装1.下载windows下的安装包2.安装3.Java中Opencv加载测试 三、Java中通过Opencv进行模板匹配大图找小图四、进行多图查找五&#xff1a;案例下载bilibili视…

碳排放预测模型 | Python实现基于机器学习回归分析的碳排放预测模型——随机森林、决策树、KNN 和多层感知器 (MLP) 预测分析

文章目录 效果一览文章概述研究内容环境准备源码设计KNNRandom ForestDecision TreeMLPModel Evaluation学习总结参考资料效果一览

【Android开发基础】随机点名系统(关于读取xml资源文件)

文章目录 一、引言二、设计1、读取xml2、下拉框Spinner3、随机算法 三、实施1、子元素随机&#xff08;单位&#xff1a;班级&#xff09;2、父元素随机&#xff08;单位&#xff1a;专业&#xff09;3、指定人数随机4、指定人数混合排序 四、附件 一、引言 描述&#xff1a;这…

【手撕MyBatis源码】动态SQL全流程解析

文章目录 动态SQL概述ifchoose(when、otherwise)trim&#xff08;where、set&#xff09;foreach OGNL表达式BoundSql动态SQL主流程分析SqlNodeDynamicContext源码解析StaticTextSqlNodeTextSqlNodeIfSqlNodeChooseSqlNodeForEachSqlNode 动态脚本结构动态脚本执行 SqlSourceSt…

Spring Cloud - Eureka原理、注册、搭建、应用(全过程详解)

目录 一、Eureka 注册原理 1.1、为什么要使用 Eureka 1.2、Eureka 的工作流程及原理 1.3、eureka 的作用 二、具体实现 2.1、搭建注册中心 2.2、服务注册和部署 2.2.1、user-service 服务注册 2.2.2、服务部署 2.2.3、order-service 服务注册 2.2.4、验证服务 2.3、…

java SSM 药品集中管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM 药品集中管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代 码和数据库&#xff0c;系统主要采…

[神经网络]迁移学习-微调

一、概述 一般的有监督迁移学习分为以下三种&#xff1a; ①将训练好的模型作为特征抽取模块&#xff08;例如以resnet进行特征提取&#xff09; ②在一个相关的任务中训练后直接后直接使用(例如gpt) ③在训练好的模型基础上进行微调 此外还有无监督学习的方式 zero-shot&#…

【集群】LVS+Keepalived群集

文章目录 前言一、Keepalived的概念1. Keepalived 概述2. Keepalived 作用3. Keepalived 实现原理剖析3.1 Keepalived 工作原理3.1 VRRP协议&#xff08;虚拟路由冗余协议&#xff09; 4. Keepalived 主要模块及其作用4.1 健康检查方式&#xff08;学名&#xff1a;探针&#x…

【架构基础】正交设计四原则

数学中的正交&#xff0c;是指相互垂直的两个向量&#xff0c;简单来讲就是平面上的两个垂直线段&#xff0c;其中一个线段变长或减短或者转圈圈&#xff0c;另外一根是不变的也不影响它们的垂直度的。表现为空间的独立性&#xff0c;在软件中我们可以理解为两个只有交叉点而互…

springboot0+java+vuie个人家庭财务理财系统

。本文介绍了个人理财系统的开发全过程。通过分析个人理财系统管理的不足&#xff0c;创建了一个计算机管理个人理财系统的方案。文章介绍了个人理财系统的系统分析部分&#xff0c;包括可行性分析等&#xff0c;系统设计部分主要介绍了系统功能设计和数据库设计。 本个人理财系…