LeetCode-496 下一个更大元素

news2024/11/7 13:32:07

一、前言

今天想要分享的题目其实和之前写的股票价格那道题所用到的结构是一样的,就是单调栈,因为自己当时也对这种结构不太熟悉,看到评论区很多大佬说如果遇到要找下一个最大/最小这一类的题目,可以往单调栈这一块儿去想,这次,我们就通过LeetCode496-下一个更大元素 I和LeetCode503-下一个更大元素 II来强化一下对单调栈的影响。

二、LeetCode496

在这里插入图片描述

①暴力破解

首先这道题我们可以暴力解决,时间复杂度是O(n^2),思路很简单,我们遍历nums1,找到nums1元素和nums2元素相等的位置j(题目提到nums1的元素一定会在nums2出现),此时我们定义k=j+1;即相等的元素的后面一个元素。然后从k开始遍历nums2,如果找到nums2[k]大于nums1i 的元素,则记录nums2[k]进入结果数组,反之记录-1.

那么我们的代码如下:

class Solution {
	public int[] nextGreaterElement(int[] nums1, int[] nums2) {
		int m = nums1.length, n = nums2.length;
		int[] res = new int[m];
		for (int i = 0; i < m; i++) {
			int j = 0;
			//寻找nums1和num2元素相等的位置
			while (j < n && nums1[i] != nums2[j]) {
				j++;
			}
			int k = j + 1;
			//从k开始遍历,在k<n的前提下寻找nums2[k] > nums1[i]的元素
			while (k < n && nums2[k] < nums2[j]) {
				k++;
			}
			//找到了返回该元素,没找到返回-1
			res[i] = k < n ? nums2[k] : -1;
		}
		return res;
	}
}

在这里插入图片描述

②单调栈

那么我们有没有O(n)级别的解决方法呢,答案是有的,我们可以通过单调栈的方法解决,上一节leetCode题目我们曾经讲解过单调栈的定义,单调栈是栈中元素严格递增或者严格递减的一种特殊的栈结构,每当新元素插入时,都需要判断该元素与栈顶元素的大小关系,不断弹出栈顶元素直到满足单调性。这里不做多说。
那么这道题我们该如何使用单调栈解决这个问题呢,答案很简单,我们首先对nums2下手
我们要找比当前元素右边更大的元素,那么我们其实倒过来想是更好的,因为这样可以保证我们每一个元素确确实实的都处理到了如果正向,你其实单调栈反而不好维护。因为你不知道你的下一个元素是什么,会不会比你前一个要大,你可能就会频繁的覆盖原来的结果。或者你正向也可以,当你发现比栈顶大的,你就记录结果,但是这样的话,你会发现你所有元素都会入栈,这样不符合单调栈的思想
那么我们继续按照倒过来的思想解决:我们把它想成一个单调递减的栈,从nums2最后一个元素开始遍历,如果该元素比栈顶元素更大,就出栈,此时我们在入栈新的元素,保持栈为单调递减的。你会发现,每当进新元素的时候,只要此时栈不为空,说明存在比该元素右边第一个更大的元素,如果栈为空,那么就直接记录-1.那么我们该怎么记录呢,答案很简单,使用哈希表即可,我们哈希表每次记录以遍历的元素为key,value则是上面的逻辑,根据栈是否是空,value取栈顶或者-1;,然后将遍历的元素入栈。至此,一次循环完毕,遍历第二个元素,以此类推。
最后我们以nums1的每个元素为key,在哈希表找对应value即可。

那测试用例nums1 = [4,1,2], nums2 = [1,3,4,2]来画图举个例子:
在这里插入图片描述
根据上述逻辑,我们返回res结果为[-1,3,-1].
代码如下:

class Solution {
	public int[] nextGreaterElement(int[] nums1, int[] nums2) {
		int m = nums1.length;
		int n = nums2.length;
		HashMap<Integer,Integer> hashRes = new HashMap<>();
		Deque<Integer> arrayDeque = new ArrayDeque<>();
		int[] res = new int[m];
		for (int i = n - 1;i >= 0; i--) {
			while (!arrayDeque.isEmpty() && nums2[i]>arrayDeque.peekLast()){
				arrayDeque.pollLast();
			}
			hashRes.put(nums2[i],arrayDeque.isEmpty()?-1:arrayDeque.peekLast());
			arrayDeque.addLast(nums2[i]);
		}
		for (int i = 0; i < res.length; i++) {
			res[i] = hashRes.get(nums1[i]);
		}
		return res;
	}
}

这样做时间复杂度是O(m+n) -> O(n)

在这里插入图片描述

三、LeetCode503

在这里插入图片描述
那么做完上面那道题后,我们再来看一下这道题的变种,我们发现现在就一个数组了,但是这个数组变成循环数组了。
但其实这道题非常简单,我们首先想法是什么,我们可以把这个循环数组想成一个2倍长的数组,相当于把原数组复制粘贴两次到一个2倍长的数组,例如[1,2,1]就变成[1,2,1,1,2,1],这样可以很方便我们后续进行操作。然后核心思想仍然没变,单调栈,且我们仍然和上题一样,从新的数组末尾开始遍历,如果该元素比栈顶元素更大,就出栈,此时我们在入栈新的元素,保持栈为单调递减的
然后此时其实就可以不用哈希表了,之前使用哈希表是为了将Nums的位置映射到Nums1;再一个原因是此时是可以存在重复元素了,不像上题不存在重复的元素,现在我们可以直接new一个数组装新数组的结果这个新数组的长度可以是2倍数组的长度也可以是原数组的长度。如果是2倍数组的长度最后缩容即可,原数组的长度,我们可以通过(i%originalLength)去更新res的值,结果是一样的。数数组初始化时我们可以先让它的每一个元素值均为默认值-1,然后就是将上题放哈希表那一步替换为res的值的相关操作。
例如拿[1,2,1]举例,我们先通过程序复制我们的数组变成[1,2,1,1,2,1],然后new一个res,长度我用原来的数组好了,即new int[3].然后具体效果如下图:
在这里插入图片描述
根据上述逻辑,我们返回res=[2,-1.2]
代码如下:

Java
class Solution {
    public int[] nextGreaterElements(int[] nums) {
        //边界判断
		if (nums == null || nums.length <= 1) {
			return new int[]{-1};
		}
		int originalLength = nums.length;
		int[] doubledArray = new int[2 * originalLength];
		//复制数组
		for (int i = 0; i < originalLength; i++) {
			doubledArray[i] = nums[i];
			doubledArray[i + originalLength] = nums[i];
		}
		int[] result = new int[originalLength];//存放结果
		Arrays.fill(result, -1);//默认全部初始化为-1
		Deque<Integer> stack = new ArrayDeque<>();
		for (int i = doubledArray.length - 1; i >= 0; i--){
			while (!stack.isEmpty() && doubledArray[i] >= stack.peek()){
				stack.pop();
			}
			result[i % originalLength] = stack.isEmpty()?-1:stack.peek();
			stack.push(doubledArray[i]);
		}
		return result;
    }
}

那么对于上述的代码,我们可否优化呢,其实是可以的,我们其实可以免去复制数组这个步骤的
我们从刚才获取result的思想可以想到通过取余的操作去解决这个问题,即我们直接遍历原数组,只不过我们的i是从2倍数组的长度-1开始,然后每次新的元素变成nums[i%orignalLength],所以在解题思路不变的情况下,可以将上面代码变成如下做法:

class Solution {
    public int[] nextGreaterElements(int[] nums) {
		int originalLength = nums.length;
		int[] result = new int[originalLength];//存放结果
		Arrays.fill(result, -1);//默认全部初始化为-1
		Deque<Integer> stack = new ArrayDeque<>();
		for (int i = 2*originalLength - 1; i >= 0; i--){
			while (!stack.isEmpty() && nums[i%originalLength] >= stack.peek()){
				stack.pop();
			}
			result[i % originalLength] = stack.isEmpty()?-1:stack.peek();
			stack.push(nums[i%originalLength]);
		}
		return result;
    }
}

在这里插入图片描述

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

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

相关文章

CAD Exchanger SDK 3.22.0 Crack

Docker 映像、Autodesk Inventor 2022 支持以及从 CAD Exchanger 3.22.0 中的 CATIA 导入属性 使用 Docker 映像将您的软件运送到任何地方&#xff0c;独立于 Autodesk 软件读取 .ipt、.iam 文件&#xff0c;从 CATIA 探索机械、产品和自定义属性。 软件开发工具包产品更新发明…

暄桐四阶课程「自在行草」学习装备指南

在2011年&#xff0c;暄桐成立的最初&#xff0c;课程便是面向零基础的成年人设计的。在十余年的教学实践中&#xff0c;暄桐教室为同学们提供了一种系统、有趣、扎实&#xff0c;并可持续进阶的学习可能。许多同学都是在来到暄桐以后&#xff0c;才第一次拿起毛笔&#xff0c;…

138.【JUC并发编程- 03】

JUC并发编程- 03 (六)、共享模型之无锁1.问题提出(1).为什么不安全?(2).安全实现_使用锁(3).安全实现_使用CAS 2.CAS与volatile(1).CAS_原理介绍(2).CAS_Debug分析(3).volatile(4).为什么无锁效率高(5).CAS的特点 3.原子整形(1).原子整数类型_ 自增自减(2).原子整数类型_乘除模…

【建立单链表:头插法,尾插法;循环列表,带尾指针的循环链表合并(将Tb合并在Ta之后)】

文章目录 一、单链表的基本操作的实现1.建立单链表&#xff1a;头插法----元素插入在链表头部&#xff0c;也叫头插法。2.建立单链表&#xff1a;尾插法----元素插入在链表尾部&#xff0c;也叫尾插法。 二、线性表的链式表示和实现1.循环列表2.带尾指针的循环链表合并&#xf…

用自定义的QSortFilterProxyModel实现条件过滤,使qtableview中只显示满足条件的行信息

在实际开发中&#xff0c;qtableview是qt客户端页面中最常用的控件之一。运用qtableview的同时&#xff0c;也会存在着先对初始数据进行过滤&#xff0c;然后在qtableview上展示的只有满足条件的那些信息。或者在不同的条件下要展示出不同的满足条件的行信息。 第一种方法&…

电脑删除的视频怎么恢复?可尝试着3钟恢复办法!

无论是为了工作还是生活&#xff0c;我们都有可能在电脑上保存重要的视频&#xff0c;如宣传视频、回忆录视频等。这些视频通常包含了制作者的心血&#xff0c;要是被我们误删除了&#xff0c;很难重新拍摄&#xff0c;那么电脑删除的视频怎么恢复&#xff1f; 能。通常&#…

用 GPU 加速 PQC 方案:Montgomery、SHA3

参考文献&#xff1a; [DK91] Duss S R, Kaliski B S. A cryptographic library for the Motorola DSP56000[C]//Advances in Cryptology—EUROCRYPT’90: Workshop on the Theory and Application of Cryptographic Techniques Aarhus, Denmark, May 21–24, 1990 Proceeding…

Tensorboard安装及简单使用

Tensorboard 1. tensorboard 简单介绍2. 安装必备环境3. Tensorboard安装4. 可视化命令 1. tensorboard 简单介绍 TensorBoard是一个可视化的模块&#xff0c;该模块功能强大&#xff0c;可用于深度学习网络模型训练查看模型结构和训练效果&#xff08;预测结果、网络模型结构…

带头的循环双向链表的简单介绍

目录 带头的循环双向链表&#xff1a; 1、带头&#xff1a; 2、循环&#xff1a; 3、双向&#xff1a; 图例&#xff1a; 带头的双向循环链表的创建&#xff1a; 头文件部分&#xff1a; 主函数部分&#xff1a; 最终调试效果&#xff1a; 使用一级指针传参的原因&am…

异常数据检测 | Python奇异谱分析(SSA)数据缺失值插补

文章目录 文章概述模型描述源码分享参考资料文章概述 长时序栅格数据经常会出现一些缺失值,会对后续的分析造成很大的不便。这便需要利用一些插值算法对这些缺失数据进行填补,奇异谱分析(SSA)便是常用的一种插值方法。 模型描述 在时间序列分析中,「奇异谱分析」(「SS…

了解活动聊天机器人如何革新活动行业

在如今快节奏的时代&#xff0c;活动策划和管理对于任何活动的成功变得至关重要。无论是会议、展览会还是企业聚会&#xff0c;组织者都努力为参与者创造难忘的体验&#xff0c;同时确保幕后的顺利执行。然而&#xff0c;由于有许多任务需要处理且资源有限&#xff0c;管理活动…

智慧油气田方案:视频+AI识别,助力油气田生产与管理智能化转型

一、背景与挑战 根据《“十四五”能源领域科技创新规划》指出&#xff0c;要推动核心技术创新突破&#xff0c;推动煤炭、油田、电厂、电网等传统行业与数字化、智能化技术深度融合。我国油田产业已经摆脱了早期粗放式增长的阶段&#xff0c;需要更加精细化、智慧化、科学化的…

59个外贸开发信爆款标题,提高你的邮件打开率

标题是吸引读者打开邮件的第一印象&#xff0c;对于外贸销售人员来说&#xff0c;精心撰写开发信标题至关重要。客户收到的邮件那么多&#xff0c;那么在客户收件箱中的5至20个客户邮件标题中&#xff0c;你必须确保自己的标题能够脱颖而出。 下面的外贸开发信标题示例&#x…

第十四章 Iambda表达式和流处理

第十四章 Iambda表达式和流处理 14.1&#xff1a;Iambda表达式简介 Iambda表达式可以用非常少的代码来实现抽象方法。 Iambda表达式不能独立执行&#xff0c;因此必须是西安函数式接口&#xff0c;并返回一个函数式接口的对象。 Iambda表达式的语法特殊的 语法格式如下 &…

我在明白软件测试这个道理后,涨薪10万

上升期的创业型公司 vs 大厂 如何抉择&#xff1f; 最近总有一些学生特别“凡尔赛”的发几个 offer 问我选择哪个&#xff1f;其中比较典型的一个问题就是&#xff1a; “一个是处于上升期的创业型公司 &#xff0c;一个行业大厂&#xff0c;薪资待遇差不多&#xff0c;到底该…

良心推荐,超好用老师小程序

各位老师&#xff0c;今天咱就来说说一件让你们省心省力的事儿——成绩查询系统。那些年&#xff0c;咱们或许都经历过手动发布成绩的痛苦&#xff0c;但现在&#xff0c;时代变了&#xff01;咱们有了小程序可以使用了&#xff0c;学生们可以自助查询成绩&#xff0c;省去了您…

Springboot+vue的班级综合测评管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的班级综合测评管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的班级综合测评管理系统&#xff0c;采用M&#xff08…

【微信小程序开发】自定义组件以及页面布局设计 )

【微信小程序开发】自定义组件以及页面布局设计 1.创建自定义组件2...在tabs的wxml文件中定制组件模板2.1.js中定义组件的属性2.2.定义组件的相关事件2.3在其他页面引用组件2.4在使用组件的wxml页面中使用组件2.5定义属性值 三。个人中心的实现 ) 1.创建自定义组件 要新建comp…

加密货币恐怖融资惊动国会!而链上分析公司看不下去了,紧急辟谣?

巴以冲突发生后&#xff0c;关于以加密货币资助恐怖分子的争论不断。全球最大的交易所币安和稳定币发行商Tether都表示己配合冻结多个账户和地址&#xff0c;以切断哈玛斯加密金援。美国合规交易所Coinbase也在近日发表了防止加密货币非法活动的宣言&#xff0c;反加密出名的参…

Mysql第二篇---InnoDB数据存储结构

Mysql第二篇—InnoDB数据存储结构 数据库的存储结构: 页 索引结构给我们提供了高效的索引方式, 不过索引信息以及数据记录都是保存在文件上的(innodb的ibd文件, MyISAM的MyI和MyD文件), 确切的说是存储在页结构中. 另一方面, 索引是在存储引擎中实现的, MySQL服务器上的存储引…