算法题解记录10+++缺失的第一个正数

题目描述:

        给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

        请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

示例 1:

输入:nums = [1,2,0]
输出:3
解释:范围 [1,2] 中的数字都在数组中。

示例 2:

输入:nums = [3,4,-1,1]
输出:2
解释:1 在数组中,但 2 没有。

示例 3:

输入:nums = [7,8,9,11,12]
输出:1
解释:最小的正数 1 没有出现。

提示:

  • 1 <= nums.length <= 105
  • -2^31 <= nums[i] <= 2^31 - 1

解题准备:

        1.了解基本操作:既然是找到缺失的第一个正数,必然涉及遍历(查找),其它的暂时看不出来。

        2.模拟操作:

        随便提供可能的数据,并得到它们的答案,如下图。

        人眼很快能得到结果,目前看不出步骤。

图1

解题难点1分析:

        难点1:看不出步骤。

        既然我们的目标是找到缺失的第一个正数,那么朴素的思想是:

        方案1:

        定义变量x=1,对数组元素每次遍历,完成遍历后x++,只要存在x不在数组中,那么它就是答案。

        对于【1,2,3……n】这样的数据,最多遍历n*n次即可,所以时间复杂度较高约为O(n^2)

        方案2:

        如果说遍历的效率比较低,我们可以自然地想到利用Hash表,采取空间换时间的思路,来优化算法。

        简单地说,遍历一次数组,把数组的元素全部添加进Hash集合HashSet中,然后利用其方法查找缺失的正数。

        查找的思路和方案1类似,都是定义变量x=1,一遍遍查找,只要x不在集合中,就是答案。

        不过明显地,且不说遍历一次数组,和遍历一次x,一共出现了两次,时间复杂度在O(n^2)

        就单单说使用Hash集合,已经开辟了O(n)的空间复杂度,所以还是有问题。

        当然,效率自然高了很多,只是不符合题意罢了。

解题难点2分析:

        难点2:如何优化算法,保证其效率的同时,又保证其空间复杂度不过高?

        无所谓,先把题目解决了再说,即使时间空间复杂度差一些。

        其实很多人也能想到,既然我们的目标是找到缺失的、最小的正数,那么:

        问题1:如果这个数组有序,不就很好解决了吗?

        比如,对于有序数组【-2,-1,0,1,2,3,4,5,……n】,遍历一遍数组,然后找到不相连的两个数,中间的数不就是答案吗?(当然,0到第一个正数、一直连续到最后一个数、仅一个数的数组、第一个数就比1大等等特殊情况,都值得注意)

        但是这确实是一个思路。

        解决方案也很简单:首先排序一遍【排序的时间复杂度可能很高,但一般不增加空间复杂度】,随后采用遍历方法,找到第一个非0的正数D(如果没有,返回1),判断一下D和1的关系(如果大于1,返回1),随后进入循环,

        判断一下D和下一个数N的关系(如果D+1!=N,说明二者不相连,那么D+1就是答案),如果相连,那么D进一步,直到把整个数组遍历完成。

        这个算法的时间复杂度大约在O(NlogN)左右,由于在原数组基础上排序,所以空间复杂度为O(1),复杂例子可能过不去,但是也是一种思路。

排序代码:

class Solution {public int firstMissingPositive(int[] nums) {Arrays.sort(nums); // 排序int L=0, R=0; // 双指针有助于遍历while(R<nums.length && nums[R]<=0 ){R++;}L=R;  // 指向第一个正数if(R>=nums.length){return 1; // 可能没有正数,如【-2,-1】}if(L==0){if(nums[L]!=1){return 1; // 可能第一个数就比1大,如【7,8,9】}}else if(nums[L-1]<=0 && nums[L]>1){return 1; // 可能既有负数,但是第一个正数就比1大,如【-2,-1,5,6】}if(R<nums.length-1){R++; // 保证之后的操作数组不越界}while(L<nums.length){if(nums[L]==nums[R]||nums[L]+1==nums[R]){ // 判断前后是否相连,相连有相同、+1相等两种形式,如【1,1】,【1,2】L++;if(R<nums.length-1){R++;}}else{return nums[L]+1; // 不相连,返回首个正数}}return nums[L-1]+1; // 遍历结束,全部相连,返回正数}
}

解题难点3分析:        

        本题我也是看了答案,如果让我做,我并不能以题目要求做出来,不过提供给我一种新思路:

        本题特殊思路:

        一个算法,其本质是提供一条路线,使输入转变为输出,如果从输入无法解决,不妨从结果集找思路。

        思考“解题难点1分析”中的“方案1”,可以发现这种穷举是最本质的做法,其它的行为都是在其上做优化。

        从结果集入手,可以发现,对于一个长度为n的数组,其缺失的正数只有n+1种可能,分别是从1到n+1。(如果是连续的,即为n+1,如【1,2,3】,该例答案为4)。

        1.那么,我们干脆定义一个辅助数组flag,其大小为n

        2.然后遍历输入数组nums,如果nums【i】满足,>0并且<=n(因为如果>n,它一定不是缺失的最小正数),,就使flag【nums[i]-1】=true;

        3.在遍历结束后,再遍历flag,只要flag【i】==false,就说明数组nums中没有这个正数,这就是答案。

        代码:
class Solution {public int firstMissingPositive(int[] nums) {boolean[] data=new boolean[nums.length];// 不初始化的原因,是JVM自动把boolean类型的数据置为false。for(int i=0; i<nums.length; i++){if(nums[i]<=nums.length&&nums[i]>0){ // 满足两个条件data[nums[i]-1]=true;}}for(int i=0; i<nums.length; i++){if(!data[i]){return i+1; // 返回答案}}// 如果全都是true,说明答案是n+1return nums.length+1;}
}

真正的答案:

        其实该题要求辅助空间为常数级别,所以解题难点3分析中的答案,也不符合题意,不过已经非常接近了。

        由于题目不限制修改数组nums,所以可以在数组nums的角度上操作,其原理和难点3类似,不过思路又更加特别。

        1.难点3中flag的作用就是映射,将答案映射到第一个false对应的下标上。

        2.其实采用一个全为0、大小为n的数组,同样满足该目的。

        3.不如使其映射到nums上。

        难点4:怎么做到呢?nums中既有正数、又有负数。

        步骤:

        1.负数不影响结果,不妨映射到n+1上(或者0,随你),也就是:遍历nums,如果nums【i】<=0,使nums【i】=n+1或者0。

        2.再一次遍历,正数如果满足nums【i】<=n,那么使nums【nums[i]-1】=0(等于0最好判断)【错误

        问题2:如果nums【i】-1比i更大(比如8和1),那么遍历到i=nums【i】-1即8时,这个数已经被置0了,那怎么处理?

        所以,原数据不能乱变,起码要使得后来的操作可以处理。

        3.删除2,同样的思路,使nums【nums[i]-1】= nums【nums[i]-1】,这保证了可以通过绝对值,获得数据。(这也是最难的一步)

        4.最后遍历一遍数组,和遍历boolean数组一样,找到第一个非负(boolean中是false)的数,这个数下标+1就是答案。

        5.如果全都小于等于0,说明答案是n+1。

代码不在此发布,因为不是我写的。

以上内容即我想分享的关于力扣热题10的一些知识。

        我是蚊子码农,如有补充,欢迎在评论区留言。个人也是初学者,知识体系可能没有那么完善,希望各位多多指正,谢谢大家。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

初识ansible服务及ansible主机清单配置

目录 1、什么是自动化批量管理 2、自动化工具ansible架构 3、ansible服务专用术语对照表 4、设置主机清单&#xff08;inventory&#xff09; 3.1实验环境准备 3.2配置主机清单 3.2.1分组基本格式 3.2.2指定用户名&#xff0c;密码。端口 3.2.3子组 3.3查看 3.3.1看…

Pandas部分应掌握的重要知识点

目录 Pandas部分应掌握的重要知识点一、DataFrame数据框的创建1、直接基于二维数据创建&#xff08;同时使用index和columns参数&#xff09;2、基于excel文件中的数据来创建 二、查看数据框中的数据和联机帮助信息1、查看特殊行的数据2、查看联机帮助的两种常见方法&#xff0…

Web自动化测试进阶:网页中难点之等待机制 —— 强制等待,隐式等待

为什么要添加等待 避免页面未渲染完成后操作&#xff0c;导致的报错 经常会遇到报错&#xff1a;selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":&q…

SpringBoot碎片化知识

参考资料&#xff1a; java官方词典&#xff1a;https://docs.oracle.com/javase/tutorial/information/glossary.html#F苍穹外卖&#xff1a;https://www.bilibili.com/video/BV1TP411v7v6 JavaBean规范 JavaBean规范是一种类的规范&#xff0c;其要求符合下列条件&#xf…

2024 DTC大会精彩演讲:DBdoctor,基于eBPF重新定义数据库可观测 (附PPT下载和演讲视频)

由中国DBA联盟&#xff08;ACDU&#xff09;和墨天轮社区联合主办的第十三届数据技术嘉年华&#xff08;DTC&#xff09;于北京盛大召开。4月13日上午海信聚好看云平台负责人张纪宽受邀在『数据库生态软件』分论坛发表主题演讲《DBdoctor&#xff1a;利用eBPF技术实现数据库智能…

动态内存;

目录 1.malloc; 简要介绍&#xff1a; 如何使用&#xff1a; free函数&#xff1a; 2.calloc; 简要介绍&#xff1a; 与malloc的区别&#xff1a; 3.realloc; 简要介绍&#xff1a; 如何使用&#xff1a; 4.动态内存常见错误&#xff1b; 1.malloc; 简要介绍&#x…

Eureka-搭建Eureka步骤

简介&#xff1a; Eureka是Netflix开发的服务发现框架&#xff0c;本身是一个基于REST的服务&#xff0c;主要用于定位运行在AWS域中的中间层服务&#xff0c;以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中&#xff0c;以实…

【随身wifi京东金榜排名】格行vs华为vs上赞随身wifi哪款最好用?格行随身wifi官方正品,格行随身wifi怎么样?

第一名&#xff1a;格行随身wifi 综合分99.1 随身WiFi行业领跑品牌 &#xff0c;15年行业经验 &#xff0c;随身WiFi口碑榜第一名。轻便小巧&#xff0c;支持三网通&#xff0c;可以随时随地提供稳定高速的网络连接。使用目前先进的马维尔芯片&#xff0c;信号稳定&#xff0…

HashMap源码剖析

1.JDK7版本创建与添加数据的的过程 (1). HashMap<String, Integer> map &#xff1d;new HashMap<>(); //创建对象过程中&#xff0c;底层会初始化数组Entry[] table &#xff1d;new Object[16];16是2的倍数. ... map.put("hexua", 66); 将"h…

Java springmvc 参数名用is开头导致为null

因为最近在整理一些源码和编写规范&#xff0c;这里写一下只是记录几年前自己遇到的问题&#xff0c;好久都忘了&#xff0c;还是写下来比较好。 问题记录&#xff1a;由于变量使用了boolean&#xff0c;并且变量名是is开头的&#xff0c;由于java机制boolean默认是false&#…

变量---

一、变量概述 1、什么是变量 变量是用于存放数据的容器。通过变量名 获取数据&#xff0c;甚至数据可以修改。 变量的本质&#xff1a;变量是程序在内存中申请的一块用来存放数据的空间。 二、变量的使用 变量在使用时分两步&#xff1a;1、声明变量 2、赋值 三、变量语法…

【回溯】Leetcode 51. N 皇后【困难】

N 皇后 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的解决方案。…