First Missing Positive – Solution & Complexity

Solution Walkthrough

1. Understand what actually matters

  • The answer must be in the range 1..n+1 for an array of length n.
  • Negative numbers, zeros, and values larger than n cannot directly block the first missing positive.

2. Start with a set-based brute-force solution

  • Insert every value into a hash set.
  • Then scan upward from 1 until you find the first positive missing from the set.
  • This is easy to reason about, but it costs O(n) extra space.
def first_missing_positive(nums: list[int]) -> int:
    seen = set(nums)
    candidate = 1
    while candidate in seen:
        candidate += 1
    return candidate

3. Place each value where it belongs

  • Value 1 belongs at index 0, value 2 at index 1, and so on.
  • If we keep swapping each in-range value into its correct slot, the first index that disagrees with this rule reveals the answer.

4. Use cyclic placement for O(1) extra space

  • While a value is in the range 1..n and not already in its correct slot, swap it into position value - 1.
  • After that placement phase, scan left to right for the first index whose value is wrong.
def first_missing_positive(nums: list[int]) -> int:
    i = 0
    n = len(nums)
    while i < n:
        correct = nums[i] - 1
        if 1 <= nums[i] <= n and nums[correct] != nums[i]:
            nums[i], nums[correct] = nums[correct], nums[i]
        else:
            i += 1

    for index, value in enumerate(nums):
        if value != index + 1:
            return index + 1
    return n + 1

5. Dry run / placement trace

Trace nums = [3,4,-1,1].

steparrayexplanation
start[3,4,-1,1]3 belongs at index 2
swap[-1,4,3,1]put 3 into its slot
skip[-1,4,3,1]-1 is out of range, so move on
swap[-1,1,3,4]4 belongs at index 3
swap[1,-1,3,4]then 1 belongs at index 0
scan[1,-1,3,4]index 1 should contain 2, so the answer is 2

6. Common mistakes and follow-ups

  • Forgetting to keep swapping until the current slot is either invalid or correct.
  • Accessing nums[correct] before checking that the value is in the range 1..n.
  • Using a clone in a context where the interviewer asked specifically for true O(1) extra space.
  • Follow-up: can you solve the same problem with sign marking after first normalizing out-of-range values?

7. Edge cases to test mentally

  • Arrays containing only negatives should return 1.
  • [1,2,3] should return 4.
  • Duplicates like [1,1] still return 2.
  • A single [1] should return 2, while a single [2] should return 1.

8. Final full solution and complexity

Cyclic placement visits each index a constant number of times, so the optimal approach runs in O(n) time with O(1) extra space beyond the returned integer.

def first_missing_positive(nums: list[int]) -> int:
    i = 0
    n = len(nums)
    while i < n:
        correct = nums[i] - 1
        if 1 <= nums[i] <= n and nums[correct] != nums[i]:
            nums[i], nums[correct] = nums[correct], nums[i]
        else:
            i += 1

    for index, value in enumerate(nums):
        if value != index + 1:
            return index + 1
    return n + 1

FAQ