Skip to content

First Missing Positive

Problem Statement

Given an unsorted integer array nums, return the smallest missing positive integer.

You must implement an algorithm that runs in O(n) time and uses O(1) auxiliary space.

Examples

Example 1

text
Input: nums = [1, 2, 0]
Output: 3
Explanation: The numbers 1 and 2 are present, so the answer is 3.

Example 2

text
Input: nums = [3, 4, -1, 1]
Output: 2
Explanation: 1 is present but 2 is missing.

Example 3

text
Input: nums = [7, 8, 9, 11, 12]
Output: 1
Explanation: The smallest positive integer 1 is missing.

Visual Explanation

First Missing Positive Process

Key Insight: Cycle Sort / Index as Hash

The crucial observation:

  1. The answer is always in range [1, n+1] where n = len(nums)
  2. We can use the array itself as a hash table
  3. Place number i at index i-1 (if 1 <= i <= n)
  4. After placement, scan for the first index where nums[i] != i+1

This achieves O(n) time and O(1) space by using cyclic sort technique.

Solution

python
def firstMissingPositive(nums: list[int]) -> int:
    """
    Find first missing positive using cycle sort (in-place hash).

    Time Complexity: O(n) - each element placed at most once
    Space Complexity: O(1) - in-place modification
    """
    n = len(nums)

    # Place each number i at index i-1 (if valid)
    for i in range(n):
        # Keep swapping until current position has correct number or invalid
        while 1 <= nums[i] <= n and nums[nums[i] - 1] != nums[i]:
            # Swap nums[i] to its correct position
            correct_idx = nums[i] - 1
            nums[i], nums[correct_idx] = nums[correct_idx], nums[i]

    # Find first position where nums[i] != i + 1
    for i in range(n):
        if nums[i] != i + 1:
            return i + 1

    # All positions are correct, answer is n + 1
    return n + 1
java
public int firstMissingPositive(int[] nums) {
    int n = nums.length;

    // Place each number i at index i-1 (if valid)
    for (int i = 0; i < n; i++) {
        // Keep swapping until current position has correct number or invalid
        while (nums[i] >= 1 && nums[i] <= n && nums[nums[i] - 1] != nums[i]) {
            // Swap nums[i] to its correct position
            int correctIdx = nums[i] - 1;
            int tmp = nums[correctIdx];
            nums[correctIdx] = nums[i];
            nums[i] = tmp;
        }
    }

    // Find first position where nums[i] != i + 1
    for (int i = 0; i < n; i++) {
        if (nums[i] != i + 1) {
            return i + 1;
        }
    }

    // All positions are correct, answer is n + 1
    return n + 1;
}

Complexity (Cycle Sort): Time O(n) · Space O(1)

  • Time: Each element is swapped at most once to its final position; total swaps bounded by n
  • Space: In-place modification using the input array as a hash table
python
# Alternative: Mark with negative (modifies array differently)
def firstMissingPositive_marking(nums: list[int]) -> int:
    """
    Mark presence using negative sign.
    """
    n = len(nums)

    # Step 1: Replace non-positive and out-of-range with n+1
    for i in range(n):
        if nums[i] <= 0 or nums[i] > n:
            nums[i] = n + 1

    # Step 2: Mark presence by negating
    for i in range(n):
        num = abs(nums[i])
        if num <= n:
            nums[num - 1] = -abs(nums[num - 1])

    # Step 3: Find first positive (unmarked)
    for i in range(n):
        if nums[i] > 0:
            return i + 1

    return n + 1


# Brute force with set (O(n) time but O(n) space)
def firstMissingPositive_set(nums: list[int]) -> int:
    """
    Using hash set - O(n) space.
    """
    num_set = set(nums)
    i = 1
    while i in num_set:
        i += 1
    return i

Complexity (Marking): Time O(n) · Space O(1)

  • Time: Three separate O(n) passes: sanitize values, mark presence, find first positive
  • Space: In-place modification; sign bit used as presence marker

Complexity (Hash Set): Time O(n) · Space O(n)

  • Time: O(n) to build set, O(n) worst case to find first missing positive
  • Space: Set stores up to n elements from the input array

Step-by-Step Trace (Cycle Sort)

For nums = [3, 4, -1, 1]:

inums[i]Valid?ActionArray State
03Yes (1<=3<=4)Swap 3 to idx 2[-1, 4, 3, 1]
0-1No (-1<1)Move to i=1[-1, 4, 3, 1]
14Yes (1<=4<=4)Swap 4 to idx 3[-1, 1, 3, 4]
11Yes (1<=1<=4)Swap 1 to idx 0[1, -1, 3, 4]
1-1No (-1<1)Move to i=2[1, -1, 3, 4]
23At correct posMove to i=3[1, -1, 3, 4]
34At correct posDone[1, -1, 3, 4]

Final scan:

  • Index 0: nums[0]=1 == 0+1 ✓
  • Index 1: nums[1]=-1 != 1+1 ✗ -> Return 2

Why Answer is in [1, n+1]

text
Consider array of length n:

Case 1: All of 1, 2, ..., n are present
        Answer = n + 1

Case 2: At least one of 1, 2, ..., n is missing
        Answer is the smallest missing one (<= n)

Therefore, we only need to check [1, n] and return n+1 if all present.

Example:
n = 4, nums = [1, 2, 3, 4] -> Answer = 5 (n+1)
n = 4, nums = [5, 6, 7, 8] -> Answer = 1
n = 4, nums = [1, 3, 4, 5] -> Answer = 2

Complexity Analysis

ApproachTimeSpace
Cycle SortO(n)O(1)
MarkingO(n)O(1)
Hash SetO(n)O(n)

Why is cycle sort O(n)? Each element is swapped at most once to its final position.

Edge Cases

  1. Empty array: [] -> 1
  2. All negative: [-1, -2, -3] -> 1
  3. All positive consecutive: [1, 2, 3] -> 4
  4. Single element: [1] -> 2, [2] -> 1
  5. Duplicates: [1, 1, 1] -> 2
  6. Large numbers: [100, 200, 300] -> 1

Common Mistakes

  1. Not handling duplicates - Check if nums[nums[i]-1] != nums[i] to avoid infinite loop
  2. Modifying array incorrectly - Be careful with swap indices
  3. Off-by-one errors - Index is i, expected value is i+1
  4. Forgetting range check - Only place numbers in [1, n]
Find All Numbers Disappeared in an Array (LeetCode 448)

Problem: Find all numbers in [1, n] missing from array of n integers.

Key Insight: Same cycle sort / index marking pattern. Use array as hash map.

Approach: Mark presence by negating value at index (num-1). Numbers at positive indices are missing.

Complexity: O(n) time, O(1) space

Find the Duplicate Number (LeetCode 287)

Problem: Find duplicate in n+1 integers where each is in [1, n], without modifying array.

Key Insight: Treat array as linked list - values are pointers. Duplicate creates cycle.

Approach: Floyd's cycle detection (tortoise and hare). Find cycle, then find entrance.

Complexity: O(n) time, O(1) space

Set Mismatch (LeetCode 645)

Problem: Array should be [1, n] but one number duplicated and one missing. Find both.

Key Insight: Use marking technique to find duplicate. Sum math to find missing.

Approach: Mark visited by negating. Find duplicate (already negative when visiting). Use sum difference for missing.

Complexity: O(n) time, O(1) space

Missing Number (LeetCode 268)

Problem: Find missing number from [0, n] in array of n distinct numbers.

Key Insight: Use XOR or sum formula (Gauss formula: n*(n+1)/2).

Approach: XOR all indices and values - duplicate cancels, missing remains. Or: expected_sum - actual_sum.

Complexity: O(n) time, O(1) space

Key Takeaways

  • Cycle sort is powerful for in-place rearrangement problems
  • The array can serve as its own hash map (index = value - 1)
  • Always ask: "What's the range of possible answers?"
  • The constraint O(1) space + O(n) time often hints at in-place array manipulation
  • The swap condition nums[nums[i]-1] != nums[i] prevents infinite loops with duplicates