Algorithm

First Missing Positive (Cyclic Sort)

Sorting Pattern

First Missing Positive (Cyclic Sort)

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.

CONSTRAINTS
  • 1 <= nums.length <= 10⁵
  • -2³¹ <= nums[i] <= 2³¹ - 1
  • Constraint: O(n) time and O(1) space.
EXAMPLE 1
Input: nums = [1,2,0]
Output: 3
The numbers in the range [1,2] are present in the array. The smallest positive integer greater than 2 is 3.
EXAMPLE 2
Input: nums = [3,4,-1,1]
Output: 2
1 and 3 are present, but 2 is missing.
EXAMPLE 3
Input: nums = [7,8,9,11,12]
Output: 1
The smallest positive integer 1 is missing.
Is it acceptable to modify the input array in-place?
Yes. To achieve O(1) auxiliary space, you are expected to use the input array as your primary storage for state.
How should I handle negative numbers and zeros?
Treat them as 'noise'. Since we are looking for the smallest *positive* integer (1, 2, 3...), any value <= 0 can be ignored or treated the same way as values > n.
Can the array contain duplicates?
Yes. Your algorithm should handle duplicates correctly (e.g., if you have two 3s, they shouldn't cause an infinite swap loop).
What if the input array is empty?
The constraints usually specify a minimum length of 1, but if empty, the smallest missing positive would be 1.
The Logic: What is Cyclic Sort?

Cyclic Sort is a powerful pattern for problems where the input array contains a range of numbers, typically from 1 to N. The key insight is simple: if we know the values are in a specific range, we also know exactly where each value belongs.

In an "ideal" sorted array of range [1, N]:
- The number 1 belongs at index 0
- The number 2 belongs at index 1
- The number x belongs at index x - 1

Instead of comparing elements against each other (like in Quick Sort), we iterate through the array and check if the current number is at its "home" index. If it isn't, we swap it with whatever is currently at its home. We repeat this until the current index holds the correct number.

Applying Cyclic Sort to Find Missing Values

Imagine an array of size 4 containing [3, 1, 4, 3] (where numbers should be 1 to 4). We use a simple loop to place every number in its "home":

text
# Basic Cyclic Sort for range [1, N]
i = 0
WHILE i < n:
    correct_idx = nums[i] - 1
    # If the number is not at its correct home...
    IF nums[i] != nums[correct_idx]:
        SWAP(nums[i], nums[correct_idx])
    ELSE:
        i += 1

After the swaps, the array becomes [1, 3, 3, 4]. By scanning the result, we see that at index 1, there is a 3 instead of the expected 2. Conclusion: 2 is missing, and the 3 at index 1 is a duplicate.

The Main Challenge: First Missing Positive

While the 1-to-N case is straightforward, the "First Missing Positive" problem adds a layer of complexity: the array can contain negative numbers, zeros, and values much larger than the array size (N).

The Strategy: Using the Array as its own Hash Map

We can still use the Cyclic Sort logic by simply ignoring the "noise". We treat the array as a restricted hash map that only cares about the range [1, n].

1. The Selective Swap: Iterate through the array. For every number nums[i]:
- If it's in our target range [1, n] AND it's not already at its "home" (nums[nums[i]-1]), swap it there.
- If the number is <= 0 or > n, we ignore it and move on.
- We use a while loop to keep swapping until the current index i holds a number that doesn't belong in the range or is already correctly placed.
2. The Final Scan: Walk through the array once more. The first index i where nums[i] != i + 1 is our answer. If all positions are correct, the answer is n + 1.
python
def firstMissingPositive(nums):
    n = len(nums)
    for i in range(n):
        # Place nums[i] in its correct home index: nums[i] - 1
        while 1 <= nums[i] <= n and nums[nums[i] - 1] != nums[i]:
            target_idx = nums[i] - 1
            nums[i], nums[target_idx] = nums[target_idx], nums[i]
            
    # First index that doesn't hold (index + 1) is the missing value
    for i in range(n):
        if nums[i] != i + 1:
            return i + 1
            
    return n + 1
Why Cyclic Sort is the only way

Other O(N) techniques like "Sum of Range" or "XOR" fail here because the array can contain negative numbers and duplicates that disrupt the math. Cyclic Sort is purely structural—it physically moves elements to where they would be in a sorted array, making the "missing" slot immediately visible.

> Complexity Note: While there is a while loop inside a for loop, each swap puts at least one number into its final correct position. Since a number is only moved once, the total number of swaps is at most N, keeping the overall complexity O(N).

Interactive Strategy Visualization

Visual Intuition

Watch the cyclic sort process step-by-step.

3
0
1
1
4
2
2
3
STEP 1 / 16 • INIT

Starting Cyclic Sort. Each number x belongs at index x-1.

O(N log N) Sort -> O(N) HashSet -> O(N) Cyclic Sort