解题思路:
归并排序——剔重——找到最小非负数——折半查找
这道题就是需要考虑的边界比较多
另外就是对重复数字的处理
提交代码:
class Solution {
public int firstMissingPositive(int[] nums) {
if(nums.length==0) return 1;
if(nums.length==1)
return (nums[0]<=0||nums[0]>=2)?1:2;
//排序
mergeSort(nums,0,nums.length-1);
//剔重
int i=1,j=1,flagnum=nums[0];
while(i<nums.length) {
while(i<nums.length&&nums[i]==flagnum)
i++;
if(i<nums.length) {
nums[j++]=nums[i];
flagnum=nums[i++];
}
}
int len=j;
//边界
if(nums[len-1]<=0||nums[0]>=2) return 1;
if((nums[len-1]-nums[0])==(len-1))
return nums[len-1]+1;
//找到第一个0及以上的数
int mid,left=0,right=len;
int posmin=0;
while(left<=right) {
if(nums[left]>0) {
posmin=left;
break;
}
posmin=(left+right)/2;
if(nums[posmin]>0) right=posmin;
else if(nums[posmin]==0) break;
else left=posmin+1;
}
if(nums[posmin]>=2) return 1;
//此时nums[left]是0 或者1
left=posmin;right=len-1;
while(left<right) {
if(left==(right-1)) return nums[left]+1; //134567
mid=(left+right)/2;
if((mid-left)!=(nums[mid]-nums[left])) right=mid;
else if((right-mid)!=(nums[right]-nums[mid])) left=mid;
else {
if((nums[mid+1]-nums[mid])!=1) return nums[mid]+1;
else return nums[right]+1;
}
}
if(nums[left]==1) return 2;
else return nums[right]-1;
}
public void mergeSort(int[] nums,int left,int right){
if(left>=right) return;
int mid=(left+right)/2;
mergeSort(nums,left,mid);
mergeSort(nums,mid+1,right);
merge(nums,left,mid,right);
}
public void merge(int[] nums,int left,int mid,int right) {
if(left==right) return;
int len=right-left+1;
int tmp[]=new int[len];
int i=left,j=mid+1,k=0;
while(i<=mid&&j<=right)
tmp[k++]=nums[i]<nums[j]?nums[i++]:nums[j++];
while(i<=mid)
tmp[k++]=nums[i++];
while(j<=right)
tmp[k++]=nums[j++];
for(k=0;k<len;k++)
nums[left++]=tmp[k];
}
}
运行结果: