缺失的第一个正数

缺失的第一个正数(难度:困难)

4

方法一(空间复杂度不满足要求)

遍历一遍数组,将元素装入HashSet,再从1开始,判断元素是否在HashSet中,若不存在,则该数为缺失的第一个正数。

复杂度

时间复杂度:O(n).

空间复杂度:O(n).

代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public int firstMissingPositive(int[] nums) {
Set<Integer> set = new HashSet<>();
for(int num:nums){
if(!set.contains(num))
set.add(num);
}

int n = 1;
while(true){
if(set.contains(n))
n++;
else
return n;
}
}
}
1

方法二

思路

通过预处理保证数组中的数全为正数,遍历数组,当读到数字 a 时,替换索引a 处元素的符号为负数。最后返回正数所对应的索引。

算法
  • 首先检查1是否存在于数组中。如果没有,则已经完成,1 即为答案。
  • 若1在数组中,则可将负数,零,和大于 n 的数替换为 1 。
  • 遍历数组。当读到数字 a 时,替换索引a 处元素的符号。(即若数组中出现1,改变nums[1]的符号;若出现2,改变nums[2]的符号) 注意重复元素:只能改变一次符号。由于遇到数字n时,没有下标 n ,则使用索引0 处的元素来保存是否存在数字 n。
  • 返回结果:
    • 从1开始遍历数组。返回第一个正数元素的下标。
    • 如果 nums[0] > 0,则返回 n 。
    • 如果之前的步骤中没有发现 nums 中有正数元素,则返回n + 1。
复杂度

时间复杂度:O(n).所有的操作一共只会遍历长度为 N 的数组 4 次。

空间复杂度:O(1).只使用了常数的空间。

代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class Solution {
public int firstMissingPositive(int[] nums) {
int n = nums.length;

if(nums.length == 0)
return 1;

// 查看数组中是否包含1
int contains = 0;
for(int i = 0; i < n; i++){
if(nums[i]==1){
contains += 1;
break;
}
}
if(contains==0)
return 1;

// 替换小于等于0的数及大于n的数为1
for(int i = 0; i<n; i++){
if(nums[i]<=0 || nums[i] > n)
nums[i] = 1;
}

// 遍历数组
for(int i=0; i<n; i++){
int a = Math.abs(nums[i]);
if(a==n)
nums[0] = -Math.abs(nums[0]);
else
nums[a] = -Math.abs(nums[a]);
}

// 返回结果(索引0处要单独判断,因为若数组中未出现n,则nums[0]处的值会为正数,但不该返回索引0)
for(int i = 1; i < n; i++){
if(nums[i]>0)
return i;
}

if(nums[0]>0)
return n;

return n+1;

}
}
3