给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。
示例 1:
输入: [1,2,0]
输出: 3
示例 2:
输入: [3,4,-1,1]
输出: 2
示例 3:
输入: [7,8,9,11,12]
输出: 1
提示:
- 你的算法的时间复杂度应为O(n),并且只能使用常数级别的额外空间。
来源:力扣(LeetCode)
分析
这道题最容易想到的办法是哈希表。但题目要求了不能用额外的空间,所以我们需要自己构造一个哈希表。
首先遍历数组,如果数组里没有1,直接返回1。
如果有1,那么就把所有小于等于0和大于n的数字全都变为1。
(因为这道题的结果一定在1到n+1之间产生,别的数字可以直接不考虑,n+1的特殊情况我们放到后面说)
此时所有数字都为正而且在1到n之间,然后就到了最核心的构造哈希表环节了:我们用这些数字减1的值作为下标去寻找数字。具体实现如下:
遍历数组,把遍历到的数字作为索引,把该索引-1的位置取负。比如数组现在是[3,4,1,1]。遍历第一次把第三个数字(3-1=2,下标为2的数字)变为-1,数组变为[3,4,-1,1];第二次把第四个数字(4-1=3)变为-1,数组变为[3,4,-1,-1];注意到第三次nums[2]变为-1了,因此要有一个取绝对值的操作,把第一个数字(|-1|-1=0)变为-3,数组变为[-3,4,-1,-1];最后一次,此时第一个数字已经是负了,我们要保证这些数字只被改一次。上面的操作变为代码只需要下面两句
for(int i=0;i<n;i++){
int a=Math.abs(nums[i])-1;
nums[a]=-Math.abs(nums[a]);
}
最后,我们发现凡是没有的数字,对应下标的数字都是正数。比如没有2,即第二个数字4是正数。我们最后遍历数组,找到第一个是正数的数字返回索引即可。
最后的最后,注意一种特殊情况,比如[1,2,3,4]。最后的结果一定所有数字都是负数,这种情况我们返回n+1即可。代码如下:
class Solution {
public int firstMissingPositive(int[] nums) {
int n=nums.length;
boolean exist1=false;
for(int i=0;i<n;i++){
if(nums[i]==1)
exist1=true;
}
if(exist1==false)
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])-1;
nums[a]=-Math.abs(nums[a]);
}
for(int i=0;i<n;i++){
if(nums[i]>0)
return i+1;
}
return n+1;
}
}