力扣刷题day50|739每日温度、496下一个更大元素 I

news2024/9/20 10:41:39

文章目录

    • 739. 每日温度
      • 暴力思路
      • 单调栈思路
        • 什么时候用单调栈?
        • 解题思路
    • 496. 下一个更大元素 I
      • 思路
        • 单调栈

739. 每日温度

力扣题目链接

给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。

示例 1:

输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]

示例 2:

输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]

示例 3:

输入: temperatures = [30,60,90]
输出: [1,1,0]

暴力思路

暴力解法,两层for循环,第一个for循环每个天数,第二个for找该天温度后面的更高温

单调栈思路

什么时候用单调栈?

  • 怎么能想到用单调栈呢? 什么时候用单调栈呢?

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

例如本题其实就是要找到一个元素右边第一个比自己大的元素

  • 那么单调栈的原理是什么呢?为什么**时间复杂度是O(n)**就可以找到每一个元素的右边第一个比它大的元素位置呢?

单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素高的元素,优点是只需要遍历一次。

  • 在使用单调栈的时候首先要明确如下几点:
  1. 单调栈里存放的元素是什么?

单调栈里**只需要存放元素的下标i**就可以了,如果需要使用对应的元素,直接T[i]就可以获取。

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

注意一下顺序为从栈顶到栈底的顺序(因为说从左到右或者从前到后,不知道栈顶和栈底是哪)

这道题中,从栈顶到栈底的顺序是递增循序,因为只有递增的时候,加入一个元素i,才知道栈顶元素在数组中右面第一个比栈顶元素大的元素是i

解题思路

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

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

用示例1的temperatures = [73, 74, 75, 71, 71, 72, 76, 73]为例来逐步分析,输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]来画图解题

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

image-20221117151722971

加入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]

image-20221117152150710

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

image-20221117152403372

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

image-20221117152656426

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

image-20221117153058307

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

image-20221117153403827

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

image-20221117153752683

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

image-20221117153851023

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

image-20221117154324239

继续弹出T[2]

image-20221117154449416

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

image-20221117154556870

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

image-20221117154725221

result[6] result[7]初始化的时候就为0(如果result没有更新,说明这个元素右面没有更大的了,也就是为0)

完整代码:

public int[] dailyTemperatures(int[] temperatures) {
    int[] res = new int[temperatures.length];

    // 定义单调栈
    Deque<Integer> stack = new LinkedList<>();
    // 空栈直接入栈
    stack.push(0);
    // 遍历每个温度
    for (int i = 1; i < temperatures.length; i++) {
        if (temperatures[i] <= temperatures[stack.peek()]) { // 如果当前遍历元素小于等于栈顶的元素
            stack.push(i);
        }else {
            // 找到大于栈内元素的时候
            while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) {
                res[stack.peek()] = i - stack.peek();
                stack.pop();
            }
            stack.push(i);
        }
    }

    return res;
}

注:想把LinkedList当做集合list,那么应该用add/remove,如果想用作队列,则使用offer/poll,如果用作栈,则使用push/pop,如果用作双端队列,则使用offerFirst/offerLast/pollFirst/pollLast。根据语义使用,就不会发生:我想删队尾,结果删了队头这种事了。

496. 下一个更大元素 I

力扣题目链接

nums1 中数字 x下一个更大元素 是指 xnums2 中对应位置 右侧第一个x 大的元素。

给你两个 没有重复元素 的数组 nums1nums2 ,下标从 0 开始计数,其中nums1nums2 的子集。

对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j]下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1

返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素

示例 1:

输入:nums1 = [4,1,2], nums2 = [1,3,4,2].
输出:[-1,3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:
- 4 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
- 1 ,用加粗斜体标识,nums2 = [1,3,4,2]。下一个更大元素是 3 。
- 2 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。

示例 2:

输入:nums1 = [2,4], nums2 = [1,2,3,4].
输出:[3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:
- 2 ,用加粗斜体标识,nums2 = [1,2,3,4]。下一个更大元素是 3 。
- 4 ,用加粗斜体标识,nums2 = [1,2,3,4]。不存在下一个更大元素,所以答案是 -1 。

思路

由题意可以指导要定义一个和nums1一样大小的数组result来存放结果。

  • 这个result数组初始化应该为多少呢?

题目说如果不存在对应位置就输出 -1 ,所以result数组如果某位置没有被赋值,那么就应该是是-1,所以就初始化为-1。

在遍历nums2的过程中,我们要判断nums2[i]是否在nums1中出现过,因为最后是要根据nums1元素的下标来更新result数组。

注意题目中说是两个没有重复元素 的数组 nums1 和 nums2

没有重复元素,我们就可以用map来做映射了。根据数值快速找到下标,还可以判断nums2[i]是否在nums1中出现过。

// 把nums1装入map
HashMap<Integer, Integer> hashMap = new HashMap<>();
for (int i = 0 ; i< nums1.length ; i++){
    hashMap.put(nums1[i],i);
}

单调栈

  • 为什么要用单调栈呢?因为我们要找nums1中元素的右边第一个更大的元素,而nums1中的元素都是存在于nums2中的。
  • 所以当我们发现nums2中的某个元素是大于前面元素的时候时,就判断这个元素是不是同样存在于nums1中,如果在nums1中,那就可以记录下当前的大元素到结果数组中

使用单调栈,首先要想单调栈是从大到小还是从小到大。

栈头到栈底的顺序,要从小到大,也就是保持栈里的元素为递增顺序。只要保持递增,才能找到右边第一个比自己大的元素。

接下来就要分析如下种情况,将nums2的元素入栈

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

此时满足递增栈(栈头到栈底的顺序),所以直接入栈。

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

如果相等的话,依然直接入栈,因为我们要求的是右边第一个比自己大的元素,而不是大于等于!

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

此时如果入栈就不满足递增栈了,这也是找到右边第一个比自己大的元素的时候。

判断栈顶元素是否在nums1里出现过,(注意栈里的元素是nums2的元素),如果出现过,开始记录结果。

记录结果的逻辑是:此时栈顶元素在nums2中右面第一个大的元素是nums2[i]当前遍历元素

完整代码

public int[] nextGreaterElement(int[] nums1, int[] nums2) {
    int[] res = new int[nums1.length];
    Arrays.fill(res, -1);

    // 把nums1装入map  key:下标元素,value:下标
    HashMap<Integer, Integer> map = new HashMap<>();
    for (int i = 0 ; i < nums1.length ; i++){
        map.put(nums1[i], i);
    }

    // 定义单调栈
    Deque<Integer> stack = new LinkedList<>();
    stack.push(0);
    for (int i = 1; i < nums2.length; i++) {
        if (nums2[i] <= nums2[stack.peek()]) {
            stack.push(i);
        }else {
            while (!stack.isEmpty() && nums2[i] > nums2[stack.peek()]) {
                // 看nums1里是否存在这个元素
                if (map.containsKey(nums2[stack.peek()])) {
                    // 根据map找到nums2[stack.peek()] 在 nums1中的下标
                    int index = map.get(nums2[stack.peek()]);
                    res[index] = nums2[i];
                }
                stack.pop();
            }
            stack.push(i);
        }
    }

    return res;
}

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

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

相关文章

[Games 101] Lecture 11-12 Geometry 2 (Curves and Surfaces)

Lecture 11-12 Geometry 2 (Curves and Surfaces) Curves Bzier Curves 贝塞尔曲线 使用一系列的控制点定义某个曲线&#xff0c;控制点定义曲线满足的一些性质可以定义出唯一的曲线&#xff0c;从 p0p_0p0​ 开始&#xff0c;p3p_3p3​ 结束 de Casteljau Algorithm 绘制贝…

Linux16 ---共享内存、操作函数、使用示例

一、共享内存 1、 共享内存为多个进程之间共享和传递数据提供了一种有效的方式。共享内存是先在物理内存上申请一块空间&#xff0c;多个进程可以将其映射到自己的虚拟地址空间中。 所有进程都可以访问共享内存中的地址&#xff0c;就好像它们是由 malloc 分配的一样。如果某…

(二)Easyexcel 的使用(读取数据到map集合中)

前面讲述了使用实体类的方式绑定excel表头的方式进行读取和写入操作&#xff0c;是比较简单的&#xff0c;那么由于表头可能会变&#xff0c;那么就不能使用绑定实体类的方式进行了&#xff0c;于是搜索百度一番&#xff0c;借鉴别人的博客&#xff0c;使用map集合的方式进行读…

一文详解Cookie 和 Session 会话技术

目录 Cookie Session 分布式下Seesion的不足 Cookie 定义&#xff1a;Cookie是服务器发送到浏览器&#xff0c;并保存在浏览器端的一小块数据。浏览器下次访问该服务器时&#xff0c;会自动携带该数据块&#xff0c;将其发送给服务器。 作用&#xff1a;由于HTTP是无状态的&…

tomcat修改默认端口详细步骤(包含运行测试)

前言&#xff1a; 在tomcat端口被占用或者需要把默认的8080端口换成其他的端口&#xff0c;就可以修改默认端口。 一、修改步骤 1.打开tomacat的文件位置--conf目录 2.找到server.xml右键打开方式选择记事本打开 3.找到这个文件的Connector port "8080" 大概位…

TVM 中文站正式上线!最全机器学习模型部署「参考书」它来了

内容一览&#xff1a; 近日&#xff0c;由 MLC 社区志愿者共同翻译校对的 TVM 中文文档正式发布&#xff0c;现已托管至超神经官网 Hyper.AI。 关键词&#xff1a; TVM 开源 机器学习编译器 本文首发自微信公众号&#xff1a;HyperAI超神经 面世5年&#xff0c;TVM成备受追捧的…

tensorflow2.0 学习笔记:一、神经网络计算

mooc课程Tensorflow2.0 笔记 人工智能三学派 行为主义&#xff1a;基于控制论&#xff0c;构建感知-动作控制系统&#xff08;自适应控制系统&#xff09;符号主义&#xff1a;基于算数逻辑表达式&#xff0c;求解问题时先把问题描述为表达式&#xff0c;再求解表达式&#x…

AMD EPYC(霄龙)Genoa服务器 | 综合评测

9004 | EYPC | 9654P | AMD 9654 | 7703 | Genoa | Intel 当生命科学、医药研发、东数西算、数据分析、数据挖掘、算力、数据中心、智算中心、遥感测绘、地质遥感等场景逐渐成熟&#xff0c;上层应用场景改变了底层硬件基础&#xff0c;计算、存储、网络架构的迭代升级和调整融…

win11连接共享打印机错误0x00000709

连接共享打印机出现错误0x00000709是常见的打印机错误了&#xff0c;但是用户升级到win11系统之后还遇到了同样的问题&#xff0c;这该如何解决&#xff1f;今天小编就给大家带来详细的解决办法&#xff0c;一起来看看。 方法一、卸载补丁 Win10卸载有问题的补丁KB5006667或KB5…

java项目-第145期ssm汽车在线销售系统-java毕业设计_计算机毕业设计

java项目-第145期ssm汽车在线销售系统-java毕业设计_计算机毕业设计 【源码请到资源专栏下载】 今天分享的项目是《ssm汽车在线销售系统》 该项目分为2个角色&#xff0c;管理员和用户。 用户可以浏览前台,包含功能有&#xff1a; 首页、车辆信息、新闻资讯、留言反馈、我的、跳…

OpenCV图像处理——直方图

总目录 图像处理总目录←点击这里 十二、直方图 12.1、原理 cv2.calcHist(images,channels,mask,histSize,ranges) images: 原图像图像格式为 uint8 或 float32。当传入函数时应 用中括号 [] 括来例如[img]channels: 同样用中括号括来它会告函数我们统幅图 像的直方图。如果…

电容笔哪个品牌好?十大电容笔知名品牌

如今&#xff0c;电容笔越来越受欢迎&#xff0c;性能也越来越好。如何挑选出一款物美价廉的电容笔&#xff0c;就成了一件非常头疼的事情。许多人将其用于日常生活&#xff0c;所以人们都在寻找更好、更经济的电容笔。那么&#xff0c;电容笔的牌子是最便宜、最值得我们入手呢…

骁龙AR2平台解析:分布式架构开启轻量化AR眼镜新时代

在今天的骁龙峰会2022上&#xff0c;高通面向轻量化AR眼镜推出了专属SoC&#xff1a;第一代骁龙AR2平台&#xff0c;这套方案将骁龙XR1、骁龙XR2的单片式方案&#xff0c;改为多芯片分布式SoC方案&#xff0c;同时融合了分离式渲染&#xff0c;实现一整套的AR/VR与智能手机、PC…

Leetcode 学习记录 数组和字符串 习题2

搜索插入位置 给定一个有序数组nums&#xff0c;数组中没有重复元素。搜索指定元素target在数组中插入位置。题目说如果target存在于数组中&#xff0c;直接返回index&#xff0c;如果不在返回应该插入的位置。要求在O&#xff08;logn&#xff09;的时间复杂度内完成。 因为…

DevOps Master课程总结:学习没有捷径(送DevOps安灯正确方法)

​1.摆正学习态度 “活到老&#xff0c;学到老”&#xff0c;学习是贯穿所有人一生的一件事情 。俗话说&#xff1a;“师傅领进门,修行在个人。”的意思是&#xff1a;有了师傅的指教&#xff0c;学生的技艺可以进步很快&#xff0c;但是&#xff0c;单单靠师傅是不够的&#x…

【线程】多线程编程

目录 一、概念 二、线程函数 1.pthread_create 2.pthread_exit 3.pthread_join 4.pthread_cancel 三、线程的使用 1.线程的基本操作 2.理解并发运行 一、概念 线程是程序中完成一个独立任务的完整执行序列&#xff0c;即一个可调度的实体。根据运行环境和调度者的身…

Maven基础概念【仓库和坐标】这篇看完懂了

Maven下载 官网: Welcome to Apache Maven 下载地址: Maven – Download Apache Maven 01 仓库&#xff1a; 仓库:用于存储资源&#xff0c;包含各种jar包 ​ ​ 仓库&#xff1a;用于存储资源&#xff0c;包含各种jar包 仓库分类&#xff1a; ♦ 本地仓库&#xff1a;自己电…

4_Git

一、Git学习网站 廖雪峰大神 Git 教程Git-flow 包教不包会阮一峰-常用 Git 命令清单 二、Git简介 1.Git是什么 分布式版本控制系统 2.版本控制 3.集中式 vs 分布式 4.Git简史 5.工作区、暂存区、版本库 流程 工作区&#xff1a;写代码 --> git add --> 暂存区 --…

uniapp项目搭建 请求配置

uniapp项目搭建 请求配置请求配置utils/request/index.js代码分析几个常用的方法配置文件的引入编写接口,并测试调用每个人项目用的请求接口不一样,这里就看下实现思路就好了 请求配置 在 uniapp 当中有封装好的 request 插件, request插件地址 在项目的 utils/request/index.…

【华为设备命令最全大合集,快快收藏】

01 华为交换机基础配置命令 01 常用命令视图 02 创建VLAN //用户视图&#xff0c;一般display命令查看信息比较多。 system-view //准备进入系统视图。 [Huawei]vlan 100 //创建vlan 100。 [Huawei-vlan100]quit //退回系统视图。 03 将端口加入到vlan中 [Huawei] interf…