First Missing Positive
HardPrompt
Given an unsorted integer array nums. Return the smallest positive integer that is not present in nums.
You must implement an algorithm that runs in O(n) time and uses O(1) auxiliary space.
Example 1:
Input: nums = [1,2,0]
Output: 3
Explanation: The numbers in the range [1,2] are all in the array.Example 2:
Input: nums = [3,4,-1,1]
Output: 2
Explanation: 1 is in the array but 2 is missing.Example 3:
Input: nums = [7,8,9,11,12]
Output: 1
Explanation: The smallest positive integer 1 is missing.
Constraints:
1 <= nums.length <= 105-231 <= nums[i] <= 231 - 1
Approaches
3 approaches with complexity analysis and trade-offs.
This approach involves sorting the array first. A sorted array makes it easy to find the first missing positive integer by simply iterating through it and checking for a gap in the sequence of positive numbers.
Algorithm
- Sort the input array
numsin non-decreasing order. - Initialize a variable,
expectedPositive, to1. - Iterate through the sorted array. For each number
num:- If
numis positive:- If
numis equal toexpectedPositive, we've found the number we were looking for, so we incrementexpectedPositive. - If
numis greater thanexpectedPositive, it meansexpectedPositiveis missing. ReturnexpectedPositive. - If
numis less thanexpectedPositive, it's a duplicate of a number we've already processed, so we do nothing.
- If
- If
- If the loop completes, it means all integers from
1up to the last found positive were present. The answer is the final value ofexpectedPositive.
Walkthrough
The algorithm begins by sorting the input array nums. Once sorted, we can perform a single linear scan to find the first gap in the sequence of positive integers starting from 1. We use a variable, say expectedPositive, initialized to 1. As we iterate through the sorted array, we compare each positive number with expectedPositive. If the current number matches expectedPositive, we increment expectedPositive to look for the next integer in the sequence. If we encounter a number that is greater than expectedPositive, we have found our gap, and expectedPositive is the smallest missing positive. We must also handle duplicates and non-positive numbers by skipping them appropriately. If we traverse the entire array, the answer is the final value of expectedPositive.
For example, if nums = [3, 4, -1, 1], sorting gives [-1, 1, 3, 4]. We expect 1, we find it, so we now expect 2. The next positive number is 3, which is greater than 2. Thus, 2 is the answer.
import java.util.Arrays; class Solution { public int firstMissingPositive(int[] nums) { Arrays.sort(nums); int expectedPositive = 1; for (int num : nums) { if (num > 0) { if (num == expectedPositive) { expectedPositive++; } else if (num > expectedPositive) { return expectedPositive; } // If num < expectedPositive, it's a duplicate or a smaller number // that has already been accounted for. We just ignore it. } } return expectedPositive; }}Complexity
Time
O(n log n)
Space
O(log n) to O(n)
Trade-offs
Pros
The logic is straightforward and easy to implement.
Cons
The time complexity does not meet the problem's requirement of
O(n).
This approach uses a hash set to store all the positive numbers from the input array. This allows for constant-time lookups to check for the existence of a number. We can then iterate from 1 upwards to find the first integer that is not in the set.
Algorithm
- Create a
HashSetto store positive integers. - Iterate through the input array
nums. For each number, if it's positive, add it to the hash set. - Let
nbe the length of the array. - Iterate from
i = 1up ton + 1. - In each iteration, check if
iis present in the hash set. - The first integer
ithat is not found in the set is the smallest missing positive. Returni.
Walkthrough
To achieve a linear time solution, we can use extra space in the form of a hash set. The algorithm first populates a HashSet with all the positive integers from the nums array. This step takes O(n) time as we iterate through the array once, and hash set insertion is, on average, an O(1) operation.
After building the set, we need to find the first missing positive. We know the answer must lie in the range [1, n+1], where n is the number of elements in the array. So, we simply loop from i = 1 to n + 1 and use the hash set to check for the presence of each i. The first i that is not in the set is our result. This second loop also runs in O(n) time.
For instance, with nums = [3, 4, -1, 1], the set becomes {1, 3, 4}. We then check for 1 (present), then 2 (not present), so we return 2.
import java.util.HashSet;import java.util.Set; class Solution { public int firstMissingPositive(int[] nums) { Set<Integer> set = new HashSet<>(); for (int num : nums) { if (num > 0) { set.add(num); } } int n = nums.length; for (int i = 1; i <= n + 1; i++) { if (!set.contains(i)) { return i; } } return -1; // Should not be reached }}Complexity
Time
O(n)
Space
O(n)
Trade-offs
Pros
Achieves the required
O(n)time complexity.The logic is relatively simple to follow.
Cons
Uses
O(n)auxiliary space, which violates theO(1)space constraint of the problem.
This optimal approach cleverly uses the array itself as a hash map to achieve O(n) time and O(1) space complexity. The idea is to place each number x in its correct position, which is the index x-1. After rearranging the array, a single pass can find the first missing positive.
Algorithm
- Phase 1: Rearrangement
- Iterate through the array with an index
ifrom0ton-1. - For each element
nums[i], as long as it's a valid number (1 <= nums[i] <= n) and it's not in its correct place (nums[i] != nums[nums[i] - 1]), swap it with the element at its correct index (nums[i] - 1). - This process, often called Cyclic Sort, places each number
xat indexx-1if possible.
- Iterate through the array with an index
- Phase 2: Find Missing
- Iterate through the rearranged array from
i = 0ton-1. - The first index
iwherenums[i] != i + 1indicates thati + 1is the smallest missing positive. Returni + 1.
- Iterate through the rearranged array from
- If the second loop completes without returning, it means all numbers from
1tonare present. The answer isn + 1.
Walkthrough
This approach meets both time and space constraints by modifying the array in-place. The core idea is that the first missing positive must be in the range [1, n+1]. We can therefore use the array's indices 0 to n-1 to signify the presence of numbers 1 to n.
The algorithm works in two phases. In the first phase, we iterate through the array and place each number in its correct position. For a number x, its correct position is index x-1. So, for each nums[i], if it's a number between 1 and n and it's not already at nums[nums[i]-1], we swap it. We repeat this for the element at index i until it holds a number that doesn't belong in the [1, n] range or is already in its correct spot. Despite the nested loop appearance, the total number of swaps is at most n, making this phase O(n).
In the second phase, we iterate through the modified array. The first index i where nums[i] is not equal to i+1 reveals that i+1 is the first missing positive. If we iterate through the whole array and find no such mismatch, it means all numbers from 1 to n are present, and the answer must be n+1.
class Solution { public int firstMissingPositive(int[] nums) { int n = nums.length; // Phase 1: Place each number in its correct spot int i = 0; while (i < n) { int correctIndex = nums[i] - 1; if (nums[i] > 0 && nums[i] <= n && nums[i] != nums[correctIndex]) { // Swap nums[i] with the element at its correct index int temp = nums[i]; nums[i] = nums[correctIndex]; nums[correctIndex] = temp; } else { i++; } } // Phase 2: Find the first missing positive for (i = 0; i < n; i++) { if (nums[i] != i + 1) { return i + 1; } } // If all numbers from 1 to n are present return n + 1; }}Complexity
Time
O(n)
Space
O(1)
Trade-offs
Pros
Extremely efficient, meeting both
O(n)time andO(1)space constraints.Provides an optimal solution to the problem.
Cons
The in-place manipulation can be less intuitive and trickier to implement correctly compared to other approaches.
Solutions
Solution
public class Solution { public int FirstMissingPositive ( int [] nums ) { var i = 0 ; while ( i < nums . Length ) { if ( nums [ i ] > 0 && nums [ i ] <= nums . Length ) { var index = nums [ i ] - 1 ; if ( index != i && nums [ index ] != nums [ i ]) { var temp = nums [ i ]; nums [ i ] = nums [ index ]; nums [ index ] = temp ; } else { ++ i ; } } else { ++ i ; } } for ( i = 0 ; i < nums . Length ; ++ i ) { if ( nums [ i ] != i + 1 ) { return i + 1 ; } } return nums . Length + 1 ; } }class Solution {public int firstMissingPositive(int[] nums) { int n = nums.length; for (int i = 0; i < n; ++i) { while (nums[i] >= 1 && nums[i] <= n && nums[i] != nums[nums[i] - 1]) { swap(nums, i, nums[i] - 1); } } for (int i = 0; i < n; ++i) { if (i + 1 != nums[i]) { return i + 1; } } return n + 1; }private void swap(int[] nums, int i, int j) { int t = nums[i]; nums[i] = nums[j]; nums[j] = t; }}class Solution {public: int firstMissingPositive(vector<int> &nums) { int n = nums.size(); for (int i = 0; i < n; ++i) { while (nums[i] >= 1 && nums[i] <= n && nums[i] != nums[nums[i] - 1]) { swap(nums[i], nums[nums[i] - 1]); } } for (int i = 0; i < n; ++i) { if (i + 1 != nums[i]) { return i + 1; } } return n + 1; }};class Solution: def firstMissingPositive(self, nums: List[int]) -> int: def swap(i, j): nums[i], nums[j] = nums[j], nums[i] n = len(nums) for i in range(n): while 1 <= nums[i] <= n and nums[i] != nums[nums[i] - 1]: swap(i, nums[i] - 1) for i in range(n): if i + 1 != nums[i]: return i + 1 return n + 1Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.