题目
给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。链接
思路
- 普通方法,set直接淦(/dog)
class Solution {
public int firstMissingPositive(int[] nums) {
Set<Integer>set = new HashSet<>();
int res = 1;
for(int num : nums){
set.add(num);
if(set.contains(res)){
res++;
}
}
while(set.contains(res)){
res++;
}
return res;
}
}
- 原地哈希参考大佬题解。
借用评论区大佬的解释
原地哈希就相当于,让每个数字n
都回到下标为n-1
的家里。
而那些没有回到家里的就成了孤魂野鬼流浪在外,他们要么是根本就没有自己的家(
nums[i] <= 0 || nums[i] > len
),要么是自己的家被别人占领了(出现了重复)。
这些流浪汉被临时安置在下标为
i
的空房子里,之所以有空房子是因为房子i的主人i+1
失踪了(数字i+1
缺失)。
因此通过原地构建哈希让各个数字回家,我们就可以找到原始数组中重复的数字还有消失的数字。
首先确定结果的范围在
[1, len + 1]
之间,len为数组长度
,当数组中的元素没有1时,结果为1,当数组中的元素涵盖了[1, len]
中的所有数时,结果为len + 1
。
所以可以把数组下标和数组中的元素对应起来,当
nums[i]∈[1, len]
这个区间时,对应关系为nums[i] = i + 1
,当不属于这个区间时不做操作。这样遍历一遍数组过后,即可通过下标确定数组中涵盖的[1, len]
这个区间内的数。
再次遍历数组,遇到的第一个不满足对应关系的元素的下标加一
i + 1
即为结果,否则结果为len + 1
。
class Solution {
public int firstMissingPositive(int[] nums) {
int len = nums.length;
for (int i = 0; i < len; i++) {
//这里用while是因为nums[i]交换过后的值可能仍然不满足nums[i] = i + 1
//所以需要继续交换,直到nums[i]不在[1,len]这个区间
while (nums[i] >= 1 && nums[i] <= len && nums[nums[i] - 1] != nums[i]) {
swap(nums, i, nums[i] - 1);
}
}
//遍历找到第一个不满足对应关系的元素
for (int i = 0; i < len; i++) {
if (nums[i] != i + 1) {
return i + 1;
}
}
return len + 1;
}
private void swap(int[] nums, int i, int i1) {
int temp = nums[i];
nums[i] = nums[i1];
nums[i1] = temp;
}
}