描述
给定一个未排序的整数数组nums,请你找出其中没有出现的最小的正整数
进阶: 空间复杂度 ,时间复杂度
数据范围:-231<=nums[i]<=231-10<=len(nums)<=5*105
示例1
输入:
[1,0,2]
复制返回值:
3
复制
示例2
输入:
[-2,3,4,1,5]
复制返回值:
2
复制
示例3
输入:
[4,5,6,8,9]
复制返回值:
1
题解
遍历一遍,使用hash表存放所有出现过的数字,可以只存1~n+1的值。然后从1到n+1进行遍历,第一个未出现的就是要找 的值。这个时间复杂度满足题目要求,但是空间复杂度为O(N),不满足。
牛客网提供了2种原地hash的解法
原地交换,让nums[i]的值放到其对应的索引上(网友提供)
在原数组原地交换,而我们关心的是正数,所以如果 nums[i] 是正数 > 0 且 < n 且 nums[i] 的位置上不是当前数,就把他放到应该的位置上去(防止死循环,如果原来就在正确的位置上,一直交换)。每个正数 nums[i] 的位置在 nums[i] - 1 上,即 0 的位置上放 1,以此类推(因为数组的大小是 n,那如果出现 n 放在位置 n 上会越界)。最后再遍历一遍数组,如果当前位置上的数 nums[i] 不等于 i + 1,则 i + 1 就是缺少的正整数。
如果遍历结束之后,还没有找到答案,说明所有数都在正确的位置上,是一个连续序列,那么答案就是 n + 1。
int minNumberDisappeared(vector<int>& nums) {
int n = nums.size();
for(int i=0; i<nums.size(); i++){
while(nums[i]>0 && nums[i] <=n && nums[i] != nums[nums[i]-1]){
swap(nums[i], nums[nums[i]-1]);
}
}
for(int i=0; i<n; i++){
if(nums[i] != i+1)
return i+1;
}
return n+1;
}
原地hash(官方答案)
思路:
前面提到了数组要么缺失中的某个数字,要么缺失,而数组正好有下标可以对应数字,因此只要数字中某个数字出现,我们就可以将对应下标的值做一个标记,最后没有被标记的下标就是缺失的值。
具体做法:
- step 1:我们可以先遍历数组将所有的负数都修改成n+1。
- step 2:然后再遍历数组,每当遇到一个元素绝对值不超过n时,则表示这个元素是1~n中出现的元素,我们可以将这个数值对应的下标里的元素改成负数,相当于每个出现过的正整数,我们把与它值相等的下标都指向一个负数,这就是类似哈希表的实现原理的操作。
- step 3:最后遍历数组的时候碰到的第一个非负数,它的下标就是没有出现的第一个正整数,因为它在之前的过程中没有被修改,说明它这个下标对应的正整数没有出现过。