Task:
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.
Some Questions:
What's the length of the array?
What's the range of the element?
Can I modify the array?
Solution:
//enumerate O(n^2)+O(1)
At first glance, I thought out a brute force algorithm: enumerate positive integer and check whether it is in the array.
Above algorithm runs in O(n^2) time complexity and O(1) space complexity. It doesn't meet the restriction of time complexity.
//radix-sort, O(n)+O(1<<16),
After a while, I realized that I should sort the array, I used radix-sort, then traverse the array to find the answer.
However radix-sort uses O(n) time and O(1<<16) space. I doubt whether O(1<<16) space is constant space.
//quick sort, O(nlogn)+O(1)
Another sort algorithm is quick sort, but the time complexity is O(nlogn) which doesn't meet the restriction.
At last, I realized that I can use "group sort" ,
step 1: remove non-positive element and the element larger than n (here n is the size of the array).
step 2: traverse the array, for the position nums[i]!=i, do follow operations
<span style="white-space:pre"> </span>int tmp=nums[i];
nums[i]=-1;
while(tmp>=1&&tmp<=n)
{
swap(nums[tmp],tmp);
if(nums[tmp]==tmp)break;
}
step 3: traverse the array, find the first position which nums[i]!=i, return the answer.
In this algorithm, the main complexity is in step 2. Because every element is in [1,n], so for group theory, every element will belong to one group, every element will be visited two times (one for array traverse and one for group traverse ).
So the algorithm runs in O(n) time complexity and O(1) time space perfectly.
More detail for group theory:Group_Theory from wiki
Code:
//enumerate O(n^2)+O(1)
//radix-sort, O(n)+O(1<<16),
//quick sort, O(nlogn)+O(1)
//group sort, O(n)+O(1)
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int n=nums.size();
if(nums.size()==0)return 1;
int i,j=0;
for(i=0;i<n;i++)
{
if(nums[i]>0)
{
nums[j++]=nums[i];
}
}
nums.erase(nums.begin()+j,nums.end());
n=nums.size();
nums.insert(nums.begin(),0);
for(i=1;i<=n;i++)
{
if(nums[i]==-1)continue;
else if(nums[i]!=i+1)
{
int tmp=nums[i];
nums[i]=-1;
while(tmp>=1&&tmp<=n)
{
swap(nums[tmp],tmp);
if(nums[tmp]==tmp)break;
}
}
}
for(i=1;i<=n;i++)
{
if(nums[i]!=i)break;
}
return i;
}
};