题目:
Given an unsorted integer array, find the first missing positive integer.
For example,
Given [1,2,0] return 3,
and [3,4,-1,1] return 2.
Your algorithm should run in O(n) time and uses constant space.
这道题目的是寻找第一个丢失的正数,在解题过程中主要遇到下面几种特殊的边界情况:
[1],
[2],
[-1,1],
[-1,1000],
[-1,1,1,1,2,22]
即可能两个数字之间差别很大,也可能会有重复数字出现。我看到题目的第一反应,是将其进行排序,这样可以很方便的找到丢失的正数。但是中间就遇到了这些边界情况,搞得跳了好几次。其实排序之后我们需要做的就是遍历数组,找到大于零且比前面一个正数大超过一的数字。代码入下:
public int firstMissingPositive(int[] nums) {
if(nums.length == 0 || nums == null)
return 1;
Arrays.sort(nums);
for(int i=0; i<nums.length; i++){
if(nums[i] > 0)
if(nums[i] != 1)
return 1;
else{
//判断是否为突变点,并且排除相等的情况
while(i < nums.length-1 && (nums[i+1] == nums[i]+1 || nums[i+1] == nums[i]))
i++;
return nums[i]+1;
}
}
return nums[nums.length-1]+1;
}
看到题目的同时,脑海中还有另外一种解法,那就是使用一个数组来保存遍历过的正数,这样有一个问题,比如说[-1, 1000]这种情况下,我们申请的数组不够大怎么办,后来一想,如果出现了这种情况,那说明丢失的数字肯定在这之前。也就是说,我们原本的数组大小就足以支撑,只不过需要加一个限制条件,当某个元素大于数组长度时,不要把它保存到数组当中即可。代码入下:
public int firstMissingPositive1(int[] nums) {
int n = nums.length;
//该数组用于记录原数组信息,下标记录原数组的值
int[] tmp = new int[n+2];
for(int i=0; i<n; i++){
if(nums[i] > 0 && nums[i] < n+2){
tmp[nums[i]] = 1;
}
}
for(int i=1; i<n+2; i++)
if(tmp[i] != 1)
return i;
return 1;
}
但是题目要求我们需要使用常数的存储空间。所以我们应该使用数组内部交换来实现,代码入下:
public int firstMissingPositive2(int[] A) {
int i = 0;
while(i < A.length){
if(A[i] == i+1 || A[i] <= 0 || A[i] > A.length) i++;
else if(A[A[i]-1] != A[i]) swap(A, i, A[i]-1);
else i++;
}
i = 0;
while(i < A.length && A[i] == i+1) i++;
return i+1;
}
private void swap(int[] A, int i, int j){
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}