LeetCode 41: First Missing Positive – O(n) Time and O(1) Space Java Solution

A complete explanation of the cyclic placement technique for finding the smallest missing positive integer in an unsorted array.

Krishna Shrivastava
12 views
LinkedInGithubX
0
0
LeetCode 41: First Missing Positive – O(n) Time and O(1) Space Java Solution
Listen to articleAudio version
Ad

Introduction

Finding the smallest positive integer missing from an unsorted array appears simple at first, but the problem becomes significantly more interesting because of its strict constraints.

Problem Link -: First Missing Positive

Given an unsorted integer array nums, the task is to return the smallest positive integer that does not appear in the array.

For example:

nums = [1,2,0]

The positive integers begin with:

1, 2, 3, 4, ...

Both 1 and 2 are present, while 3 is missing.

Therefore, the answer is:

3

The challenge is that the solution must run in:

O(n) time
O(1) auxiliary space

This rules out several common approaches such as sorting and using a HashSet.

Problem Statement

Given an unsorted integer array nums, return the smallest positive integer that is not present in the array.

Example

Input: nums = [3,4,-1,1]
Output: 2

The positive integers are:

1, 2, 3, 4, ...

1 exists in the array, but 2 does not.

Therefore:

Answer = 2

Another example:

Input: nums = [7,8,9,11,12]
Output: 1

Since 1 itself is missing, the answer is immediately:

1

Understanding the Important Observation

For an array of length n, the answer can never be greater than:

n + 1

Consider:

nums = [1,2,3]

The first three positive integers are present:

1, 2, 3

Therefore, the smallest missing positive integer is:

4

Since n = 3:

answer <= n + 1

This observation is the key to the optimal solution.

Numbers that are:

<= 0

or

> n

cannot directly determine the smallest missing positive number.

The useful values are only:

1 ... n

The Submitted HashSet Approach

A straightforward approach is to store every value in a HashSet and then search for the first missing positive integer.

The basic idea is:

Store all numbers
Check 1
Check 2
Check 3
...

The submitted implementation follows this idea:

class Solution {
public int firstMissingPositive(int[] nums) {

int max = Integer.MIN_VALUE;
HashSet<Integer> ms = new HashSet<>();

for (int a : nums) {
max = Math.max(a, max);
ms.add(a);
}

for (int i = 1; i <= max; i++) {
if (!ms.contains(i)) {
return i;
}
}

if (max < 0) {
return 1;
}

return max + 1;
}
}

This approach is logically valid for finding the answer, but it does not satisfy the required constraints.

Space Complexity

The HashSet can store up to n elements.

Therefore:

O(n) auxiliary space

The problem requires:

O(1) auxiliary space

So a different technique is required.

Why Sorting Is Also Not Enough

Sorting the array might appear to solve the problem easily.

For example:

[3,4,-1,1]

After sorting:

[-1,1,3,4]

The missing positive integer can then be identified by scanning the array.

However, sorting requires:

O(n log n)

time in the general case.

The problem specifically requires:

O(n)

time.

Therefore, sorting does not satisfy the required complexity either.

The Core Idea: Put Every Number in Its Correct Position

The optimal solution uses an in-place cyclic placement technique.

The important relationship is:

value 1 → index 0
value 2 → index 1
value 3 → index 2
value 4 → index 3
...

In general:

value x → index x - 1

Consider:

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

The desired arrangement for useful values is:

index: 0 1 2 3
value: 1 2 3 4

After placing the valid values into their corresponding positions, the array can become:

[1, -1, 3, 4]

Index 1 should contain:

2

but it contains -1.

Therefore:

answer = index + 1
= 1 + 1
= 2

This transforms the problem from:

Search for a missing number.

into:

Place every useful number at the position where it belongs, then find the first incorrect position.

Which Numbers Should Be Placed?

For an array of length n, only values satisfying:

1 <= nums[i] <= n

need to be placed.

Why?

Suppose:

n = 5

The answer can only be one of:

1,2,3,4,5,6

A value such as:

-4

cannot be the answer.

Similarly:

10

cannot prevent 1...6 from determining the answer.

Therefore, values outside the range [1,n] can safely remain where they are.

The Cyclic Placement Process

For every index i, check the current value:

nums[i]

If it belongs to the range:

1 <= nums[i] <= n

its correct index is:

nums[i] - 1

So the value should be swapped into:

nums[nums[i] - 1]

The process continues until the current position contains a value that either:

  1. is outside the useful range, or
  2. is already in its correct position.

Why the Duplicate Check Is Necessary

Consider:

nums = [1,1]

The value 1 belongs at index 0.

The first element is already correct.

At index 1, the value is again 1.

Trying to swap it repeatedly would cause an infinite loop because another 1 already occupies its correct position.

Therefore, the swap condition must also ensure:

nums[nums[i] - 1] != nums[i]

This duplicate check is extremely important.

Optimized Java Solution

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[nums[i] - 1] != nums[i]
) {
int correctIndex = nums[i] - 1;

int temp = nums[i];
nums[i] = nums[correctIndex];
nums[correctIndex] = temp;
}
}

for (int i = 0; i < n; i++) {

if (nums[i] != i + 1) {
return i + 1;
}
}

return n + 1;
}
}

Dry Run

Consider:

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

Array length:

n = 4

Initial Array

[3, 4, -1, 1]

At index 0:

nums[0] = 3

The correct index for 3 is:

3 - 1 = 2

Swap:

[3, 4, -1, 1]
[-1, 4, 3, 1]

The value at index 0 is now -1.

Since -1 is outside [1,4], no further placement is required for this index.

At index 1:

nums[1] = 4

Correct index:

4 - 1 = 3

Swap:

[-1, 4, 3, 1]
[-1, 1, 3, 4]

Now:

nums[1] = 1

The correct index of 1 is 0.

Swap:

[-1, 1, 3, 4]
[1, -1, 3, 4]

Now index 1 contains -1, so placement stops.

Final Arrangement

[1, -1, 3, 4]

The expected value at each index is:

index 0 → 1 ✓
index 1 → 2 ✗
index 2 → 3 ✓
index 3 → 4 ✓

The first incorrect position is:

index = 1

Therefore:

answer = index + 1
= 2

Another Example

Consider:

nums = [1,2,0]

The values 1 and 2 are already in their correct positions:

[1,2,0]

Expected arrangement:

index 0 → 1 ✓
index 1 → 2 ✓
index 2 → 3 ✗

The first incorrect position is index 2.

Therefore:

answer = 2 + 1 = 3

Edge Case: All Positive Numbers Are Present

Consider:

nums = [1,2,3]

Every position contains the expected value:

index 0 → 1
index 1 → 2
index 2 → 3

No missing value exists between 1 and n.

Therefore, the smallest missing positive integer is:

n + 1

So:

answer = 4

Edge Case: The Answer Is 1

Consider:

nums = [7,8,9,11,12]

All values are greater than 1.

After the placement phase, there is no 1 at index 0.

Therefore:

answer = 1

Complexity Analysis

The algorithm uses the array itself to store values in their correct positions.

Time Complexity

Although the algorithm contains a nested while loop, the total number of swaps is bounded by O(n) because every successful swap places a useful value into its correct position.

Therefore:

Time Complexity: O(n)

Space Complexity

No additional data structure proportional to the input size is used.

Only a few variables are required:

Space Complexity: O(1)

This satisfies the required constraints.

Why the Algorithm Works

The central invariant is:

Whenever a value x lies in the range [1,n], the algorithm attempts to place it at index x-1.

After the placement phase, every value that can occupy a meaningful position is either:

at its correct index

or

absent from the array

Therefore, scanning from left to right provides a direct answer.

If:

nums[i] != i + 1

then i + 1 is missing.

If every position is correct, then all values from:

1 ... n

exist, making:

n + 1

the smallest missing positive integer.

Interview Insight

This problem is an important example of in-place array positioning.

The key pattern is:

Value x
Correct index = x - 1

Whenever an array problem asks for a missing, duplicate, or misplaced number within a known range, it is worth checking whether the values themselves can be mapped directly to indices.

This technique appears in several interview problems involving:

  1. Missing numbers
  2. Duplicate numbers
  3. Cyclic sort
  4. In-place rearrangement
  5. Frequency representation without extra memory

The biggest clue in this problem is the combination of:

Unsorted array
+
O(n) time
+
O(1) space
+
Positive integers

That combination strongly suggests an in-place index/value mapping strategy.

Conclusion

LeetCode 41, First Missing Positive, is a classic example of turning the array itself into auxiliary storage.

A HashSet provides an easy solution but requires O(n) extra space. Sorting simplifies the search but requires O(n log n) time. The optimal solution instead uses the relationship:

value x → index x - 1

to rearrange useful values directly inside the input array.

After this placement, the first index whose value does not match index + 1 identifies the smallest missing positive integer.

The final complexity is:

O(n) time
O(1) auxiliary space

making the approach suitable for the strict constraints and an important pattern to recognize in technical interviews.

Ai Assistant Kas