Reference: LeetCode
Difficulty: Hard
Problem
Given an unsorted integer array, find the smallest missing positive integer.
Example:
1 | Input: [1,2,0] |
Follow up: Your algorithm should run in $O(n)$ time and uses constant extra space.
Analysis
Basic Idea: Since there are only n spaces in the array, we have the follow different cases (n = 5):
[1, 2, 3, 4, 5]: Return6. (n + 1)[1, 2, 2, 4, 5]: Return3. ([1, n])[1, 2, -1, 2, 5]: Return3. ([1, n])
The invariant is that the smallest positive integer must be in the interval [1, n + 1].
Brute-Force
For each value in [1, n], check if it is in nums.
- If it does not exist, return the corresponding index
i. - If all values in
[1, n]exist in the array, returnn + 1.
1 | public int firstMissingPositive(int[] nums) { |
Time: $O(N^2)$
Space: $O(1)$
Hash Set
The brute-force approach could be optimized by using a hash set.
1 | public int firstMissingPositive(int[] nums) { |
Time: $O(N)$
Space: $O(N)$
In-place Optimization
We can actually use the values in the array to indicate if the values from 1 to n exists.
1 | Input: [3, 4, -1, 1] |
For example, since 3 exists, we set the value (-1) at 3 - 1 to negative.
Before this process, we should traverse the array, setting all non-positive numbers and out-of-bound numbers to 1. In the above example, the output of preprocessing will be [3, 4, 1, 1].
Since we set those values to 1, during the first iteration, we must check if 1 exists. If it does not exist, the result is going to be 1. No further action should be made.
Then we process the array [3, 4, 1, 1], the output is [-3, 4, -1, -1]. In the final pass, we find that 4 is positive. So the element is the index of 4 plus one, which is 2.
Note: When using val as index, remember to use the absolute value because it might be set to negative in advance.
1 | public int firstMissingPositive(int[] nums) { |
Time: $O(N)$
Space: $O(1)$