问题描述
给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。原题链接
数据范围:
1 <= nums.length <= 5 * 105
-231 <= nums[i] <= 231 - 1
思路与方法
初见此题首先想到的是哈希,用一个和nums数组长度相同的布尔数组来表示数字1到n(n为nums数组长度)是否出现,出现了则将对应位置标为true,然后遍历布尔数组,第一个为false的位置对应数就是答案。但题目要求空间复杂度为O(1),故尝试在原数组上进行哈希,由于期望标记的数范围是1到n,所以不在此范围的数可以修改为任意大于n的正数,然后就可以通过给负号来标记出现的正数,但同时又可以通过绝对值来知道它原本的值,最后遍历数组,第一个不为负的下标对应的数为答案。
完整流程如下:
1.第一遍遍历数组,将所有不在1到n范围内的数修改为n+1;
2.第二遍遍历数组,若当前数绝对值在1到n范围内,则将以该绝对值-1为下标的正数取负(若已为负数则不再取负);
3.第三遍遍历数组,第一个为正的数下表+1即是没有出现过的最小正数。
Code
public int firstMissingPositive(int[] nums) {
int n=nums.length;
for(int i=0;i<n;i++){
if(nums[i]<1||nums[i]>n)nums[i]=n+1;
}
for(int i=0;i<n;i++){
int tmp=Math.abs(nums[i]);
if(tmp>=1&&tmp<=n&&nums[tmp-1]>0)//若为正,取负
nums[tmp-1]=-nums[tmp-1];
}
for(int i=0;i<n;i++){
if(nums[i]>0)return i+1;
}
return n+1;
}
复杂度分析
三次遍历原数组,每一次都是O(n)的时间,所以总的时间复杂度还是O(n),内存上是在原数组上作修改,只用了常数量级的空间,空间复杂度为O(1)。