First Missing Positive
return missing positive number
First Missing Positive
Problem
You are given an unsorted integer array nums. Return the smallest positive integer that is not in nums.
Your algorithm must run in O(n) time and use O(1) extra space.
Examples
Example 1
Input: nums = [1,2,0]
Output: 3
- The numbers
1and2are in the array. - The next number,
3, is missing.
Example 2
Input: nums = [3,4,-1,1]
Output: 2
1is in the array, but2is missing.
Example 3
Input: nums = [7,8,9,11,12]
Output: 1
- The smallest positive number,
1, is missing.
Constraints
1 <= nums.length <= 10^5-2^31 <= nums[i] <= 2^31 - 1
Main Idea
If the array has n numbers, the answer is always between 1 and n + 1.
- If the array has all of
1, 2, ..., n, the answer isn + 1. - Otherwise, one number between
1andnis missing, and the smallest missing one is the answer.
So numbers that are <= 0 or > n do not matter. We only care about numbers from 1 to n.
Solution 1: Using a Set
First we put all numbers in a Set. Then we check 1, 2, 3, ... one by one until we find a number that is not in the set.
var firstMissingPositive = function (nums) {
let set = new Set(nums);
let max = Math.max(...nums);
// check every number from 1 to max
for (let i = 1; i <= Math.max(max, 1); i++) {
if (!set.has(i)) {
return i;
}
}
// all numbers from 1 to max are present
return max + 1;
};
How the Code Works
setstores all numbers, so we can check "is this number here?" inO(1)time.maxis the biggest number in the array.- We check numbers from
1up tomax. The first number not in the set is the answer. - If the loop ends, every number from
1tomaxis present, so the answer ismax + 1. - If
maxis0or negative,Math.max(max, 1)makes the loop check1. It is not in the set, so we return1.
Complexity
- Time Complexity:
O(n)- Building the set takes
O(n). - The loop runs up to
maxtimes. In the worst case this can be bigger thann, but it stops at the first missing number, and there can be at mostn + 1checks before that happens.
- Building the set takes
- Space Complexity:
O(n)- The set stores up to
nnumbers.
- The set stores up to
Important: This solution does not meet the problem rule. The problem asks for
O(1)extra space, but the set usesO(n). It is a good first solution, but the next one is the one the problem wants.Tip:
Math.max(...nums)passes every number as an argument. With very large arrays, this can cause a "Maximum call stack size exceeded" error. A simple loop to find the max is safer.
Solution 2: Place Each Number at Its Correct Index (O(1) Space)
The idea is to use the array itself as a hash table.
- The number
1should be at index0. - The number
2should be at index1. - In general, the number
xshould be at indexx - 1.
We move each number to its correct place. After that, we scan the array. The first index i where nums[i] !== i + 1 tells us that i + 1 is missing.
Steps
- For each index
i, look atnums[i]. - While
nums[i]is between1andn, and it is not already at its correct place, swap it to its correct place. - Ignore numbers that are
<= 0or> n. - After all swaps, scan the array. The first index
iwithnums[i] !== i + 1gives the answeri + 1. - If every index is correct, the answer is
n + 1.
Code
var firstMissingPositive = function (nums) {
let n = nums.length;
for (let i = 0; i < n; i++) {
// keep moving nums[i] until it is in the right place
// or it is a number we do not care about
while (
nums[i] >= 1 &&
nums[i] <= n &&
nums[nums[i] - 1] !== nums[i]
) {
let correctIndex = nums[i] - 1;
// swap nums[i] with the number at its correct index
let temp = nums[correctIndex];
nums[correctIndex] = nums[i];
nums[i] = temp;
}
}
// find the first place where the number is wrong
for (let i = 0; i < n; i++) {
if (nums[i] !== i + 1) {
return i + 1;
}
}
// all numbers from 1 to n are present
return n + 1;
};
How the Code Works
Step 1: Move numbers to their correct place
nums[i] >= 1 && nums[i] <= nmeans the number is useful. Only these numbers can be the answer's neighbors.nums[nums[i] - 1] !== nums[i]checks that the correct place does not already hold the same number.- This check also stops the loop when there are duplicates. Without it, two equal numbers would swap forever.
- Inside the loop, we save
correctIndexfirst, and then swap with atempvariable.- We save
correctIndexbefore the swap, becausenums[i]changes during the swap.
- We save
Step 2: Scan for the first wrong place
- After Step 1, every useful number sits at its correct index.
- The first index where
nums[i] !== i + 1means the numberi + 1is missing.
Step 3: Return n + 1
- If no index is wrong, then
1tonare all present. So the answer isn + 1.
Dry Run
Let us take nums = [3, 4, -1, 1]. Here n = 4.
i | Action | Array after the step |
|---|---|---|
0 | 3 belongs at index 2. Swap with -1. | [-1, 4, 3, 1] |
0 | -1 is not useful. Stop. | [-1, 4, 3, 1] |
1 | 4 belongs at index 3. Swap with 1. | [-1, 1, 3, 4] |
1 | 1 belongs at index 0. Swap with -1. | [1, -1, 3, 4] |
1 | -1 is not useful. Stop. | [1, -1, 3, 4] |
2 | 3 is already at index 2. Stop. | [1, -1, 3, 4] |
3 | 4 is already at index 3. Stop. | [1, -1, 3, 4] |
Now we scan the array:
- Index
0has1. This is correct. - Index
1has-1, but it should be2. So the answer is2.
Complexity
- Time Complexity:
O(n)- The
whileloop is inside aforloop, so it may look likeO(n²). - But each swap puts one number in its final correct place, and that number is never moved again.
- So there are at most
nswaps in total, and the scan at the end takesO(n).
- The
- Space Complexity:
O(1)- We only use a few variables. We reuse the input array, so there is no extra table.
Note: This solution changes the input array. If you must keep the original array, you need to make a copy, which costs
O(n)space.
Comparison
| Approach | Time Complexity | Space Complexity | Meets the problem rule? |
|---|---|---|---|
| Set | O(n) | O(n) | No (space is O(n)) |
| Place at correct index | O(n) | O(1) | Yes |
Summary
- The answer is always in the range
1ton + 1, wherenis the length of the array. - The Set solution is easy and runs in
O(n)time, but it usesO(n)space. So it does not follow the problem rule. - The best solution uses the array as a hash table. The number
xbelongs at indexx - 1.- We swap each useful number to its correct place.
- We ignore numbers that are
<= 0or> n. - The first index where
nums[i] !== i + 1gives the answeri + 1. - If all places are correct, the answer is
n + 1.
- The duplicate check
nums[nums[i] - 1] !== nums[i]stops infinite swaps. - The best solution runs in
O(n)time and usesO(1)space.