41. First Missing Positive
Problem Description
The LeetCode problem asks for the smallest missing positive integer from an unsorted integer array nums
. The challenge is to write an algorithm that can find this number efficiently, with the constraint that the algorithm should have a time complexity of O(n)
and a space complexity of O(1)
, which means the solution must run in linear time and use a constant amount of extra space.
Intuition
The intuition behind the solution comes from the realization that the smallest missing positive integer must be within the range [1, n+1], where n
is the length of the array. This is because, in the worst case, the array contains all consecutive positive integers from 1 to n. Hence, the smallest missing positive integer would be just outside this range, which is n + 1.
To find this number within the given constraints, we apply the concept of placing each number in its 'correct position'. If nums
contains a number x
where 1 <= x <= n
, x
should be placed at index x-1
. By swapping elements to their correct positions (when they are not already there), we aim to have an array where the element at each index i
is equal to i + 1
.
Once the placement process is complete, we perform a final linear scan. If we find an index i
where nums[i]
is not equal to i + 1
, then i + 1
is our missing positive, as the number i + 1
is not in its correct position (which would be the index i
). If all elements are in their correct positions, it means our array contains all numbers from 1 to n, so the smallest missing positive integer is n + 1
.
Solution Approach
The implementation of the solution leverages the fact that we only care about positive integers up to n
, the length of the array. The key operations are swaps and a final scan to identify which positive integer is missing.
Here’s a step-by-step breakdown:
- Iterate through the array (
nums
), and for each element, perform the following actions:- Check if the current element is a positive integer and it’s within the range
[1, n]
. - Ensure that it is not already in the correct position (meaning the element at the index
nums[i] - 1
should benums[i]
itself).
- Check if the current element is a positive integer and it’s within the range
- If an element meets the above criteria, swap it with the element at its “correct” position (the position it would have if all the elements
[1, n]
were sorted), which is indexnums[i] - 1
. This is done using the helper functionswap(i, j)
. - Repeat the process until the current element is out of range or already in the correct position.
- After the swapping loop, the array is scanned again from the beginning to find the first index
i
wherenums[i]
is not equal toi + 1
. This indexi
indicates thati + 1
is the smallest missing positive integer because all the integers beforei + 1
are already in their correct positions, andi + 1
is the first one that is missing from its correct position. - If no such index
i
is found, it means all integers from1
ton
are present and in their correct positions, so the smallest missing positive integer isn + 1
.
The algorithm employs the input array itself as the data structure to store information, which is why it’s able to achieve O(1)
auxiliary space complexity, while still keeping the time complexity at O(n)
due to the linear number of operations performed.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's take an example array to illustrate the solution approach: nums = [3, 4, -1, 1]
.
-
We start by iterating through the array. The length of the array
n = 4
. -
The first element
nums[0]
is3
, which is a positive integer and within the range[1, n]
. The correct position for3
is at index2
(3 - 1 = 2
). Sincenums[2]
is-1
, we swapnums[0]
withnums[2]
. Now the array looks like this:nums = [-1, 4, 3, 1]
. -
Next, we look at the element in the current index
0
which is now-1
. Since-1
is negative and not in the range[1, n]
, we move to the next index. -
At index
1
, the element is4
, which is greater thann
and does not need to be placed within the range[1, n]
. So we move on. -
At index
2
, the element is3
and is already in its correct position (index 2 + 1 = 3
), so we move forward. -
At index
3
, we have the number1
, which should be at index0
(1 - 1 = 0
). We swapnums[3]
withnums[0]
. The array now becomes:nums = [1, 4, 3, -1]
. -
At this point, we have iterated through the entire array, placing all positive integers within the range
[1, n]
in their correct positions. -
We now perform a final scan through the array. At index
0
, we havenums[0] = 1
, which is the correct placement. -
At index
1
, we should have2
, but instead, we havenums[1] = 4
. This tells us that2
is the smallest missing positive integer because it is not at its correct position—which would be index1
. -
We conclude that
2
is the smallest missing positive integer in the arraynums
.
The array after processing is nums = [1, 4, 3, -1]
, and the smallest missing positive integer is 2
.
Solution Implementation
1class Solution:
2 def firstMissingPositive(self, nums: List[int]) -> int:
3 # Function to swap elements at indices i and j
4 def swap_elements(index1, index2):
5 nums[index1], nums[index2] = nums[index2], nums[index1]
6
7 # Get the length of the list
8 list_length = len(nums)
9
10 # Iterating through the list to place numbers on their correct positions
11 for i in range(list_length):
12 # Continuously swap the current element until it's in its correct position
13 # or it's out of range [1, n]
14 while 1 <= nums[i] <= list_length and nums[i] != nums[nums[i] - 1]:
15 swap_elements(i, nums[i] - 1)
16
17 # After placing each element in its correct position, or as correct as possible,
18 # traverse the list to find the first missing positive integer
19 for i in range(list_length):
20 # If the current number isn't the right number at index i, return i + 1,
21 # because it is the first missing positive integer
22 if i + 1 != nums[i]:
23 return i + 1
24
25 # If all previous positions contain the correct integers,
26 # then the first missing positive integer is n + 1
27 return list_length + 1
28
1class Solution {
2 public int firstMissingPositive(int[] nums) {
3 int size = nums.length;
4
5 // Iterate over the array elements.
6 for (int i = 0; i < size; ++i) {
7 // While the current number is in the range [1, size] and it is not in the correct position
8 // (Which means nums[i] does not equal to nums[nums[i] - 1])
9 while (nums[i] > 0 && nums[i] <= size && nums[i] != nums[nums[i] - 1]) {
10 // Swap nums[i] with nums[nums[i] - 1]
11 // The goal is to place each number in its corresponding index based on its value.
12 swap(nums, i, nums[i] - 1);
13 }
14 }
15
16 // Now that nums is reorganized, loop through the array
17 // to find the first missing positive number.
18 for (int i = 0; i < size; ++i) {
19 // If the number doesn't match its index (+1 because we are looking for positive numbers),
20 // that index (+1) is the first missing positive number.
21 if (nums[i] != i + 1) {
22 return i + 1;
23 }
24 }
25
26 // If no missing number found within [1, size], return size + 1 as the first missing positive number
27 return size + 1;
28 }
29
30 // Helper method to swap two elements in an array
31 private void swap(int[] nums, int firstIndex, int secondIndex) {
32 int temp = nums[firstIndex];
33 nums[firstIndex] = nums[secondIndex];
34 nums[secondIndex] = temp;
35 }
36}
37
1#include <vector>
2using namespace std;
3
4class Solution {
5public:
6 // Function to find the first missing positive integer in an array.
7 int firstMissingPositive(vector<int>& nums) {
8 int size = nums.size(); // Get the size of the array
9
10 // Process each element in the array
11 for (int i = 0; i < size; ++i) {
12 // Continue swapping elements until the current element is out of bounds
13 // or it is in the correct position (value at index i should be i + 1)
14 while (nums[i] >= 1 && nums[i] <= size && nums[nums[i] - 1] != nums[i]) {
15 // Swap the current element to its correct position
16 swap(nums[i], nums[nums[i] - 1]);
17 }
18 }
19
20 // After rearranging, find the first position where the index does not match the value
21 for (int i = 0; i < size; ++i) {
22 if (nums[i] != i + 1) {
23 // If such a position is found, the missing integer is i + 1
24 return i + 1;
25 }
26 }
27
28 // If all positions match, the missing integer is size + 1
29 return size + 1;
30 }
31
32private:
33 // Helper function to swap two elements in the array
34 void swap(int& a, int& b) {
35 int temp = a;
36 a = b;
37 b = temp;
38 }
39};
40
1function firstMissingPositive(nums: number[]): number {
2 const size = nums.length; // Store the length of the array
3
4 // Iterate over the array to place each number in its correct position if possible
5 for (let currentIndex = 0; currentIndex < size; currentIndex++) {
6 // Calculate the target position for the current number
7 const targetIndex = nums[currentIndex] - 1;
8
9 // While the current number is in the range of the array indices,
10 // is not in its target position, and is not a duplicate,
11 // swap it with the number at its target position
12 while (
13 nums[currentIndex] > 0 &&
14 nums[currentIndex] <= size &&
15 nums[currentIndex] !== nums[targetIndex] &&
16 currentIndex !== targetIndex
17 ) {
18 // Swap the current number with the number at its target index
19 [nums[currentIndex], nums[targetIndex]] = [nums[targetIndex], nums[currentIndex]];
20 // Update the target index based on the new number at the current index
21 targetIndex = nums[currentIndex] - 1;
22 }
23 }
24
25 // After reordering, find the first number that is not at its correct index
26 // The index + 1 gives the missing positive integer
27 for (let index = 0; index < size; index++) {
28 if (nums[index] !== index + 1) {
29 return index + 1; // +1 to convert index to positive integer
30 }
31 }
32
33 // If all numbers are at their correct indices, then return the size + 1
34 return size + 1;
35}
36
Time and Space Complexity
Time Complexity
The time complexity of the code is O(n)
, which is linear with respect to the number of elements in the array nums
. Within the first for loop, each element in nums
that is within the range [1, n]
is potentially swapped to its corresponding position (where the value v
should be at index v - 1
). Even though there is a while loop inside the for loop, each element can be swapped at most once because once an element is in its correct position, it no longer satisfies the while loop condition. Since each element is swapped at most once, the series of swaps can be considered to have a complexity of O(n)
.
After that, a second for loop runs which again is of complexity O(n)
. This loop does not contain any other loops or operations that would increase the time complexity. Therefore, considering both loops, the time complexity remains O(n)
.
Space Complexity
The space complexity of the code is O(1)
, which is constant space because the code only uses a fixed number of extra variables (for the swap function and for iterating over the elements of the array). The swaps are done in place and do not require any additional space that scales with the input size.
Learn more about how to find time and space complexity quickly using problem constraints.
You are given an array of intervals where intervals[i] = [start_i, end_i]
represent the start and end of the ith
interval. You need to merge all overlapping intervals and return an array of the non-overlapping intervals that cover all the intervals in the input.
Recommended Readings
LeetCode Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!