HashSet
这道题让我们找缺失的首个正数,由于限定了O(n)的时间,所以一般的排序方法都不能用,最开始我没有看到还限制了空间复杂度,所以想到了用HashSet来解,这个思路很简单,第一遍遍历数组把所有的数都存入HashSet中,并且找出数组的最大值,下次循环从1开始递增找数字,哪个数字找不到就返回哪个数字,如果一直找到了最大的数字,则返回最大值+1,代码如下:
//使用hashset来保存所有正数
public int firstmissingpositive(int[] arr) {
//记录最大正数
int max = 0;
HashSet<Integer> hs = new HashSet<>();
for(int i : arr) {
if(i<0) continue;
hs.add(Integer.valueOf(i));
max = Math.max(max, i);
}
for(int i = 1;i<=max;i++) {
if(!hs.contains(Integer.valueOf(i))) return i;
}
return max+1;
}
覆盖原数组(本质是桶排序)
上面的解法不是O(1)的空间复杂度,所以我们需要另想一种解法,既然不能建立新的数组,那么我们只能覆盖原有数组,我们的思路是把1放在数组第一个位置arr[0],2放在第二个位置arr[1],即需要把arr[i]放在arr[arr[i] - 1]上,那么我们遍历整个数组,首先要求arr[i]为正数且不大于n,如果arr[i]不等于arr[arr[i] - 1]的话,我们将两者位置调换,如果不满足上述条件直接跳过,最后我们再遍历一遍数组,如果对应位置上的数不正确则返回正确的数,即arr[i] !=i+1,代码如下:
public int firstmissingpositive2(int[] arr) {
int n = arr.length;
/*
* 第一遍遍历原数组,将每个值arr[i]放在arr[arr[i]-1]的位置,如果已经在arr[arr[i]-1]的位置了,
* 则不需要移动,如果不在则就跟原本arr[arr[i]-1]的元素互换位置
*/
for(int i = 0;i<n;i++) {
//这里必须arr[i]<=n,不然会出现数组越界
while(arr[i]>0&&arr[i]<=n&&arr[arr[i]-1]!=arr[i]) {
int temp = arr[i];
arr[i] = arr[arr[i]-1];
//这里arr[i]用temp替代,因为arr[i]已经被修改了
arr[temp-1] = temp;
}
}
/*
* 遍历重新赋值后的数组,如果出现了arr[i-1]!=i则返回i
*/
for(int i = 1;i<=n;i++) {
if(arr[i-1]!=i) return i;
}
return n+1;
}