Leetcode41. 缺失的第一个正数
Leetcode41. 缺失的第一个正数
题目描述
给你一个未排序的整数数组 nums
,请你找出其中没有出现的最小的正整数。
**进阶:**你可以实现时间复杂度为 O(n)
并且只使用常数级别额外空间的解决方案吗?
示例 1:
1 | 输入:nums = [1,2,0] |
示例 2:
1 | 输入:nums = [3,4,-1,1] |
示例 3:
1 | 输入:nums = [7,8,9,11,12] |
提示:
解题思路
这道题如果不规定时间复杂度和空间复杂度的话就是简单题。
方法一:哈希表法
如果抛开时间复杂度和空间复杂度的限制,我们自然想到可以用哈希表来记录数组中出现的元素,然后从1
开始遍历[1,len]
之间的正整数,如果哪一个没有被记录,那就是第一个缺失的元素。如果遍历结束都没返回,说明前len
个整数都没有缺失,直接返回len+1
。
示例代码如下:
1 | int firstMissingPositive(vector<int>& nums) |
时间复杂度为:
空间复杂度为:
方法二:原地哈希法
如果要达到规定的时间复杂度和空间复杂度,那么我们就要自己原地实现哈希算法。
容易发现的是,要找的数一定是在区间[1,len+1]
(len
是数组的长度)中。因为,如果在数组中有个元素比len
大,那么在[1,len]
中一定存在确实的数。不然的话,前len
个数都存在,就返回len+1
。
由于,要找的数一定是在区间[1,len+1]
中,所以我们可以将原始的数组当成哈希表。在原地实现哈希算法。这个哈希算法也比较简单,**将k
这个数重新放在下标为k-1
的位置。**也就是说,只要数i+1
存在,原始数组的下标i
处就放置数i+1
。这样的话,下标[0,len-1]
的数组就映射为了[1,len]
,最后的时候只要遍历一遍数组,如果对应规则不对,就返回映射过去的数;如果遍历结束还没返回答案,就返回len+1
。
在实现哈希函数的时候,用while
循环去实现,并且要保证数都在特定范围之内,超出范围的直接舍弃就好。
具体细节见示例代码:
1 | int firstMissingPositive(vector<int>& nums) |
时间复杂度:
虽然有两个循环,但是其实while
循环不会每一次都把数组里面的所有元素都看一遍。如果有一些元素在这一次的循环中被交换到了它们应该在的位置,那么在后续的遍历中,由于它们已经在正确的位置上了,代码再执行到它们的时候,就会被跳过。所以时间复杂度为。
空间复杂度: