缺失的第一个正数(难度:困难)
方法一(空间复杂度不满足要求)
遍历一遍数组,将元素装入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; } } }
|
方法二
思路
通过预处理保证数组中的数全为正数,遍历数组,当读到数字 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; int contains = 0; for(int i = 0; i < n; i++){ if(nums[i]==1){ contains += 1; break; } } if(contains==0) return 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]); }
for(int i = 1; i < n; i++){ if(nums[i]>0) return i; } if(nums[0]>0) return n; return n+1;
} }
|