Find missing number
LeetCode ↗ Java source ↗ Edit this article ↗
Jump to code:
Problem
You are given an array nums of n distinct integers, each in the range 0 .. n. Exactly one value from that range is absent; return it.
The A2Z sheet phrases the same problem with values 1 .. N and an array of length N - 1; the Java file includes missingFromOneToN for that wording, and every approach below carries over with the range shifted by one.
Constraints: 0 ≤ n ≤ 10^5, so the sum 0 + 1 + ... + n can reach about 5 × 10^9 and no longer fits in an int.
Example 1
nums = [3, 0, 1]
answer = 2 // n = 3, range 0..3, the only value absent is 2
Example 2
nums = [0, 1]
answer = 2 // the missing value can be n itself
Example 3
nums = [9, 6, 4, 2, 3, 5, 7, 0, 1]
answer = 8
The problem looks like a search, and the first two approaches treat it as one. The last two notice that it is really an accounting problem: we know exactly what the complete set should be, so comparing the complete set with what we have reveals the missing item without searching for anything.
Approach 1: Brute force, search for every candidate
Intuition. For each value candidate in 0 .. n, scan the array to see whether it is present. The first candidate that is not found is the answer. This is n + 1 linear searches.
Algorithm.
- For
candidatefrom0ton: - Scan
nums; if some element equalscandidate, mark it present and stop scanning. - If
candidatewas not found, return it.
static int bruteForce(int[] nums) {
int n = nums.length;
for (int candidate = 0; candidate <= n; candidate++) {
boolean present = false;
for (int x : nums) {
if (x == candidate) { present = true; break; }
}
if (!present) return candidate;
}
return -1; // unreachable for valid input
}
Complexity. Time O(n^2): up to n + 1 candidates, each costing up to n comparisons. Space O(1).
For n = 10^5 that is 10^10 operations in the worst case (the missing value is n). The tests only run this method on small inputs for that reason.
Approach 2: Better, mark what you have seen
Intuition. Instead of searching the array once per candidate, read the array once and record which values occur in a boolean table indexed by value. Then the missing value is the first index that was never marked. This trades O(n) extra memory for a factor of n in time; it is the “hashing” solution, and because the values are small non-negative integers, a plain array is the perfect hash.
Algorithm.
- Allocate
seenof sizen + 1, allfalse. - For each
xinnums, setseen[x] = true. - Return the first
vin0 .. nwithseen[v] == false.
static int better(int[] nums) {
int n = nums.length;
boolean[] seen = new boolean[n + 1];
for (int x : nums) seen[x] = true;
for (int v = 0; v <= n; v++) {
if (!seen[v]) return v;
}
return -1; // unreachable for valid input
}
Complexity. Time O(n): two linear passes. Space O(n) for the table.
This is also the approach that degrades most gracefully when the problem’s promises are broken: if the input has duplicates or several missing values, the table still tells you exactly which values are absent.
Approach 3: Optimal, the sum formula
Intuition. The sum of 0 .. n is n(n + 1) / 2. The array contains every one of those values except one, so expectedSum - actualSum is precisely the missing value. One pass, one subtraction, no extra memory.
The arithmetic must be done in long. With n = 10^5 the expected sum is 5,000,050,000, which exceeds Integer.MAX_VALUE (2,147,483,647). Writing n * (n + 1) / 2 in int overflows before the division and produces garbage; the cast (long) n must come first so that the multiplication happens in 64 bits.
Algorithm.
expected = n(n + 1) / 2computed inlong.actual = sum of numsaccumulated inlong.- Return
expected - actual.
static int optimalSum(int[] nums) {
int n = nums.length;
long expected = (long) n * (n + 1) / 2;
long actual = 0;
for (int x : nums) actual += x;
return (int) (expected - actual);
}
Dry run on nums = [3, 0, 1]: n = 3, expected = 3 × 4 / 2 = 6, actual = 3 + 0 + 1 = 4, answer 6 - 4 = 2.
Complexity. Time O(n), space O(1).
Approach 4: Optimal, XOR cancellation
Intuition. XOR has two properties that make it a counting device for “appears an odd number of times”: x ^ x = 0 and x ^ 0 = x, and it is commutative and associative, so order does not matter. XOR together all the values 0 .. n and all the elements of the array. Every value that is present appears twice (once from the range, once from the array) and cancels to zero. The missing value appears exactly once, from the range only, and survives.
This avoids the overflow question entirely: XOR never produces a result wider than its inputs.
Algorithm.
xor = 0.- For each index
i, fold in bothiandnums[i]:xor ^= i ^ nums[i]. After the loop, indices0 .. n - 1and all array values are included. - The index
nhas no array slot, so fold it in separately: returnxor ^ n.
static int optimalXor(int[] nums) {
int xor = 0;
for (int i = 0; i < nums.length; i++) xor ^= i ^ nums[i];
return xor ^ nums.length; // the index n has no array slot, fold it in separately
}
Dry run on nums = [3, 0, 1]: the folded values are 0, 3, 1, 0, 2, 1 from the loop and then 3. Pairing them up: 0 ^ 0 = 0, 1 ^ 1 = 0, 3 ^ 3 = 0, leaving 2. Answer 2.
Complexity. Time O(n), space O(1).
Sum and XOR are equally fast; XOR is the one to show when you want to signal that you know the overflow pitfall exists, and it generalises to Find the number that appears once, and other numbers twice., where no sum formula is available.
The 1 .. N wording
static int missingFromOneToN(int[] nums, int N) {
int xor = 0;
for (int v = 1; v <= N; v++) xor ^= v;
for (int x : nums) xor ^= x;
return xor;
}
Same cancellation argument with the range 1 .. N. Here N must be passed in because it is no longer recoverable from the array length alone in a way the reader will find obvious (N = nums.length + 1).
Edge cases and pitfalls
- The missing value is
n.[0, 1]must return2. The boolean table needs sizen + 1, the sum formula must includen, and the XOR must fold innafter the loop; forgetting any of these returns0or crashes. - The missing value is
0.[1, 2, 3, 4, 5]returns0: the sum difference is15 - 15 = 0and the XOR cancels completely. Both are correct, but note that0is also what a buggy XOR that forgot to fold innwould produce for the wrong reason, so test both cases. n = 0. The array is empty and the range0 .. 0contains only0, which is missing. Every method returns0.- Overflow in the sum. The product
n * (n + 1)overflowsintoncenis around46,341, and the sum itself passesInteger.MAX_VALUEatn = 65,536. The test withn = 70,000and missing value54,321catches anintversion: the wrapped expected sum is off by a multiple of2^31and the result is garbage. (Be careful when designing such a test: for some sizes,n = 100,000among them, the two wrap-arounds happen to cancel and anintversion passes by luck.) Accumulateactualinlongtoo; the partial sums exceedintjust as much. - Duplicates or several missing values. The promises make the problem well-defined; break them and the sum and XOR methods return a meaningless number. Only the marking approach can report what actually went wrong.
- Values outside
0 .. n.seen[x]throwsArrayIndexOutOfBoundsExceptionon such input. That is a feature: it fails loudly on data that violates the contract. - Operator precedence in
xor ^= i ^ nums[i]. Compound assignment has the lowest precedence, so this readsxor = xor ^ (i ^ nums[i]), which is what we want; XOR is associative, so the grouping would not matter anyway.
Related problems
- Find the number that appears once, and other numbers twice. is the pure form of the XOR cancellation trick.
- Find the repeating and missing number has one value missing and one duplicated; sums of values and of squares, or a partitioned XOR, solve it.
- Linear Search is the primitive the brute force repeats
n + 1times. - Union of two sorted arrays is the previous problem on the sheet.