Searching & Sorting · 7 of 36
Find the repeating and the missing
The numbers 1 to n should each appear once, but one shows up twice and one is gone; find both.
- Simple way
- time O(n^2)
room O(1) - Clever way
- time O(n)
room O(1)
The problem, simply
You get an array of n numbers. It should hold every number from 1 to n exactly once, in any order. But one number r appears twice, and so one number m is missing.
Return both: the repeating number and the missing number.
A story to remember it
Picture it
1 appears twice and 5 is missing. The sum is 4 short of 21 because a 5 was swapped for a 1.
- answer
- rejected
Examples
A normal case
- In
[4, 3, 6, 2, 1, 1]- Out
repeating 1, missing 5
1 shows up twice and nobody has 5.
Smallest case
- In
[2, 2]- Out
repeating 2, missing 1
With n = 2, the 1 was replaced by a second 2.
Missing the last number
- In
[1, 2, 2]- Out
repeating 2, missing 3
The missing number can be n itself.
Repeat next to the gap
- In
[3, 1, 3]- Out
repeating 3, missing 2
Order does not matter, only which numbers are there.
Way 1: the simple way
For every number v from 1 to n, count how many boxes hold it. A count of 2 means v repeats. A count of 0 means v is missing.
class Solution {
public int[] findTwoElement(int[] arr) {
int n = arr.length, repeating = -1, missing = -1;
for (int v = 1; v <= n; v++) {
int count = 0;
for (int x : arr) if (x == v) count++;
if (count == 2) repeating = v;
if (count == 0) missing = v;
}
return new int[] { repeating, missing };
}
}How long it takes: n numbers, each counted over n boxes, O(n^2). Extra room: O(1).
Way 2: the clever way
Use two clues, both easy to compute in one walk:
- Sum clue. The real sum of 1 to
nisn(n+1)/2. The array's sum minus that isr - m, becausercame in an extra time andmnever did. - Square clue. The real sum of squares is
n(n+1)(2n+1)/6. The array's squares minus that isr*r - m*m, which equals(r - m)(r + m). - Divide the square clue by the sum clue to get
r + m. - Now
r = ((r - m) + (r + m)) / 2, andm = r - (r - m).
Two sums give two clues, and two clues give two answers
01 / 10
If nothing were wrong, the boxes would hold 1 to 6. Those add up to 21, and their squares add up to 91.
- should sum
- 21
- should squares
- 91
- looking now
- seen
- answer
- rejected
class Solution {
public int[] findTwoElement(int[] arr) {
long n = arr.length;
long sum = 0, squares = 0;
for (int x : arr) {
sum += x;
squares += (long) x * x;
}
long diff = sum - n * (n + 1) / 2; // r - m
long sqDiff = squares - n * (n + 1) * (2 * n + 1) / 6; // r*r - m*m
long both = sqDiff / diff; // r + m
long r = (diff + both) / 2;
long m = r - diff;
return new int[] { (int) r, (int) m };
}
}How long it takes: one walk over the array, O(n). Extra room: a few numbers, O(1). The array is not changed.
Another way: mark the boxes
Use the array itself as a checklist. When you see value v, make box v - 1 negative, as a tick. If box v - 1 is already negative, v is the repeat. At the end, the one box that is still positive is the missing number's box.
After ticking, every box is negative except box 4, so 5 never showed up. While ticking, the second 1 found box 0 already negative, so 1 repeats.
- answer
- rejected
class Solution {
public int[] findTwoElement(int[] arr) {
int repeating = -1, missing = -1;
for (int i = 0; i < arr.length; i++) {
int v = Math.abs(arr[i]);
if (arr[v - 1] < 0) repeating = v; // already ticked: seen before
else arr[v - 1] = -arr[v - 1]; // tick box v - 1
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] > 0) missing = i + 1; // never ticked
arr[i] = Math.abs(arr[i]); // put the array back
}
return new int[] { repeating, missing };
}
}This is also O(n) time and O(1) room, and it cannot overflow, but it writes into the input while it works.
Watch out for
- Getting the sign backwards.
sum - expectedisr - m, which is negative when the repeat is smaller than the missing number. Keep the sign; the formulas handle it. - The order of the answer. GeeksforGeeks wants
[repeating, missing]. Check what your judge expects. - In the marking way, read
Math.abs(arr[i]), because the box you are reading may already have been ticked.
What interviewers ask next
- Can you do it with XOR? XOR all values and all of 1 to
n. Pairs cancel, leavingr XOR m. Split every number by one bit whererandmdiffer, XOR each group, and you getrandm. Check which one appears in the array to tell them apart. - What if the array is read-only and big? The math way only reads, so it is the answer.
- Only a missing number, nothing repeated? Expected sum minus actual sum. Or XOR, which never overflows.
- Find the duplicate in
n + 1numbers from 1 tonwithout changing the array (LeetCode 287)? Treat values as arrows to positions and use fast and slow pointers to find the loop.
Remember this
Grown-up words: the two clues are a system of two equations, the sum formulas are arithmetic series, ticking boxes by making them negative is in-place index marking, and the XOR trick uses the lowest set bit to split the numbers.