Lesson 90 of 164
First Missing Positive
Given an unsorted array of integers (which may include negatives, zeros, and duplicates), return the smallest positive integer that isn't in the array.
LeetCode: 41. First Missing Positive
Example
Input: [2, 3, -7, 6, 8, 1, -10, 15] Output: 4
Input: [3, 2, -1, 1] Output: 4
Input: [7, 8, 9, 11, 12] Output: 1The answer is always between 1 and n + 1: an array of n elements can hold at most the values 1 to n, and if it holds all of them, the answer is n + 1.
Brute force: check 1, 2, 3, ...
public class Main {
static boolean contains(int[] nums, int k) {
for (int x : nums) {
if (x == k) return true;
}
return false;
}
static int firstMissingPositive(int[] nums) {
int k = 1;
while (contains(nums, k)) k++;
return k;
}
public static void main(String[] args) {
System.out.println(firstMissingPositive(new int[]{2, 3, -7, 6, 8, 1, -10, 15}));
System.out.println(firstMissingPositive(new int[]{3, 2, -1, 1}) + " " + firstMissingPositive(new int[]{7, 8, 9, 11, 12}));
}
}4
4 1Time: O(n²): up to n + 1 candidates, each a linear search. Space: O(1).
Better: a HashSet
import java.util.HashSet;
import java.util.Set;
public class Main {
static int firstMissingPositive(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int x : nums) set.add(x);
int k = 1;
while (set.contains(k)) k++;
return k;
}
public static void main(String[] args) {
System.out.println(firstMissingPositive(new int[]{2, 3, -7, 6, 8, 1, -10, 15}));
System.out.println(firstMissingPositive(new int[]{3, 2, -1, 1}) + " " + firstMissingPositive(new int[]{7, 8, 9, 11, 12}));
}
}4
4 1Time: O(n) on average. Space: O(n).
Optimal: put each value at its own index
The array itself can be the hash table. Only values in 1 to n matter, and value v has a natural home: index v - 1. Swap every such value into its home. Afterwards, the first index i with nums[i] != i + 1 gives the answer i + 1.
[3, 2, -1, 1]
i = 0: 3 goes to index 2 -> [-1, 2, 3, 1] -1 has no home, move on
i = 1: 2 is home
i = 2: 3 is home
i = 3: 1 goes to index 0 -> [1, 2, 3, -1] -1 has no home, move on
first mismatch: index 3 -> answer 4public class Main {
static int firstMissingPositive(int[] nums) {
int n = nums.length;
for (int i = 0; i < n; i++) {
// Keep swapping until nums[i] has no home or its home already holds the right value.
while (nums[i] >= 1 && nums[i] <= n && nums[nums[i] - 1] != nums[i]) {
int home = nums[i] - 1;
int tmp = nums[i];
nums[i] = nums[home];
nums[home] = tmp;
}
}
for (int i = 0; i < n; i++) {
if (nums[i] != i + 1) return i + 1;
}
return n + 1;
}
public static void main(String[] args) {
System.out.println(firstMissingPositive(new int[]{2, 3, -7, 6, 8, 1, -10, 15}));
System.out.println(firstMissingPositive(new int[]{3, 2, -1, 1}) + " " + firstMissingPositive(new int[]{7, 8, 9, 11, 12}));
System.out.println(firstMissingPositive(new int[]{1, 1}) + " " + firstMissingPositive(new int[]{1, 2, 3}));
}
}4
4 1
2 4Time: O(n): every swap puts one value into its home for good, so there are at most n swaps in total. Space: O(1).
The check nums[home] != nums[i] stops the loop on duplicates: in [1, 1], the second 1 would otherwise swap with the first forever.
Edge cases
- No positives: the answer is
1. - All of
1tonpresent: the answer isn + 1. - Mutating the input: this version reorders the array. Copy it first if the caller needs the original order.
