First Missing Positive
Problem
nums, find the smallest positive
integer that does not appear in it. The required solution runs in O(n) time using
O(1) auxiliary space.[1,2,0]Output3[3,4,-1,1]Output2[7,8,9,11,12]Output11 ≤ n ≤ 105 · -231 ≤ nums[i] ≤ 231-1 · must be O(n) time, O(1) extra space
Try it yourself
class Solution {
public int firstMissingPositive(int[] nums) {
}
}
v at
index v-1.Instinct "In place", "O(1) extra space" or "one pass" over an array? Think write pointer, reversal, prefix/suffix passes or using indices as storage.
Memory hack Read fast, write slow, reverse to rotate, and let the index be the hash.
Open the Array Manipulation guide →Approaches
Brute ForceCheck 1, 2, 3, … by Scanning
O(n2)Space O(1)Try candidates i = 1..n+1 in order; for each, scan the whole array.
The first candidate not found is the answer — at most n+1 candidates are needed.
public int firstMissingPositive(int[] nums) { int n = nums.length; for (int i = 1; i <= n + 1; i++) { boolean found = false; for (int num : nums) { if (num == i) { found = true; break; } } if (!found) return i; } return -1; // unreachable }
Constant space, but quadratic time.
BetterHash Set Lookup
O(n)Space O(n)Load every value into a HashSet for O(1) membership tests, then walk
1, 2, …, n+1 and return the first one missing.
public int firstMissingPositive(int[] nums) { Set<Integer> set = new HashSet<>(); for (int num : nums) set.add(num); for (int i = 1; i <= nums.length + 1; i++) { if (!set.contains(i)) return i; } return -1; // unreachable }
Linear time, but O(n) extra memory violates the constraint.
OptimalCyclic Sort (In-Place Placement)
O(n)Space O(1)While nums[i] is in [1, n] and not already at its home
index nums[i]-1, swap it home. Every swap settles one value permanently, so
there are ≤ n swaps in total. Then the first index with
nums[i] ≠ i+1 gives the answer.
public int firstMissingPositive(int[] nums) { int n = nums.length; for (int i = 0; i < n; i++) { // the duplicate check stops infinite swaps of equal values while (nums[i] > 0 && nums[i] <= n && nums[nums[i] - 1] != nums[i]) { int home = nums[i] - 1; int temp = nums[home]; nums[home] = nums[i]; nums[i] = temp; } } for (int i = 0; i < n; i++) { if (nums[i] != i + 1) return i + 1; } return n + 1; }
Dry run[3,4,-1,1]
- i=0-1i4313 → idx 2; -1 stops
- i=1-11i344 → idx 3
- i=11-1i341 → idx 0; -1 stops
- i=2,31-134ialready home
- scan1-1i34idx1 ≠ 2 → 2 ✔
Linear time, in-place — meets both constraints (mutates the input).
v by making
nums[v-1] negative (after replacing non-positives with n+1).At a glance
| Level | Approach | Time | Space |
|---|---|---|---|
| Brute Force | Check 1, 2, 3, … by Scanning | O(n2) | O(1) |
| Better | Hash Set Lookup | O(n) | O(n) |
| Optimal | Cyclic Sort (In-Place Placement) | O(n) | O(1) |
- Swap guard
nums[i] != i+1instead ofnums[nums[i]-1] != nums[i]— loops forever on duplicates. - Forgetting to return
n+1when 1..n are all present. - Indexing with an out-of-range value — check
1 ≤ v ≤ nbefore swapping.
- State the [1, n+1] bound first — it is what makes O(1) space possible.
- Argue the amortised O(n): each swap places one value at its final index.
- Ask whether mutating the input is allowed before going in-place.