Arrays: Find the Missing and Repeating Number (4 Comprehensive Approaches)
Given an array of integers where each element is supposed to be in the range , exactly one integer appears twice (the Repeating Number ) and one integer is completely omitted (the Missing Number ). The goal is to identify both and and return them in the specific format [Repeating, Missing].
1. Problem Statement & Conceptual Grounding
Input Constraints & Characteristics
- An array
arrof size . - The array contains values that should ideally represent all numbers from to .
- Repeating Number (): Appears times in the array.
- Missing Number (): Appears times in the array.
- All other numbers appear exactly time.
Concrete Example Walkthrough
Consider and the input array: arr = [4, 3, 6, 2, 1, 1]
Comparing the given array against the expected set of numbers from to :
Expected Numbers : 1, 2, 3, 4, 5, 6
Actual Array : 4, 3, 6, 2, 1, 1
- Count of
1: times Repeating Number () - Count of
2: time - Count of
3: time - Count of
4: time - Count of
5: times Missing Number () - Count of
6: time
Target Output: [1, 5]
2. Core Mental Model & Solution Evolution
To solve this problem efficiently in technical interviews, you start with the most intuitive naive solution and progressively optimize both time and space complexity:
3. Approach 1: Brute Force ( Time, Space)
Method Intuition
Iterate through every candidate integer from to . For each integer , traverse the entire array to count how many times it appears.
- If
count == 2, then is the repeating number (). - If
count == 0, then is the missing number ().
Code Implementation (C++)
#include <vector>
using namespace std;
vector<int> findMissingRepeatingBruteForce(vector<int>& arr) {
int n = arr.size();
int repeating = -1, missing = -1;
for (int i = 1; i <= n; i++) {
int cnt = 0;
for (int j = 0; j < n; j++) {
if (arr[j] == i) {
cnt++;
}
}
if (cnt == 2) repeating = i;
else if (cnt == 0) missing = i;
// Early exit if both numbers are found
if (repeating != -1 && missing != -1) break;
}
return {repeating, missing};
}
Complexity Analysis
- Time Complexity: — For each number from to , we iterate through the array of size .
- Space Complexity: — Only auxiliary variables (
repeating,missing,cnt) are used.
4. Approach 2: Better Strategy using Hashing ( Time, Space)
Method Intuition
Instead of scanning the array repeatedly to count occurrences, we can use a frequency/hash array of size initialized to .
- Perform a single pass over
arrto populate the hash array:hash[arr[i]]++. - Perform a second pass over indices to in the hash array:
- Index with value
2is (Repeating). - Index with value
0is (Missing).
- Index with value
Frequency Tracking Flow
Code Implementation (C++)
#include <vector>
using namespace std;
vector<int> findMissingRepeatingHashing(vector<int>& arr) {
int n = arr.size();
vector<int> hash(n + 1, 0);
// Step 1: Pre-fill frequency array
for (int i = 0; i < n; i++) {
hash[arr[i]]++;
}
int repeating = -1, missing = -1;
// Step 2: Identify missing and repeating elements
for (int i = 1; i <= n; i++) {
if (hash[i] == 2) repeating = i;
else if (hash[i] == 0) missing = i;
if (repeating != -1 && missing != -1) break;
}
return {repeating, missing};
}
Complexity Analysis
- Time Complexity: — One pass to count frequencies and one pass to scan the hash array.
- Space Complexity: — Requires an extra array of size .
5. Approach 3: Optimal Strategy 1 — Mathematical Equations ( Time, Space)
Method Intuition
To eliminate the auxiliary space, we construct two algebraic equations with two variables:
- Let = Repeating Number
- Let = Missing Number
We use the sum of natural numbers and sum of squares of natural numbers to build a system of linear equations.
Mathematical Formulation
Equation 1: Sum Difference ()
- Sum of array elements:
- Sum of first natural numbers:
Equation 2: Sum of Squares Difference ()
- Sum of squares of array elements:
- Sum of squares of first natural numbers:
Since , we can derive :
Solving for and
Now we have two simple equations:
Adding equation (1) and equation (2):
Substituting back into equation (1):
Important Real-World Pitfall: When working with values where , and will exceed standard 32-bit integer boundaries (). Always use 64-bit integers (
long longin C++ /longin Java) to prevent overflow during calculations.
6. Step-by-Step Mathematical Walkthrough
Trace with Example: arr = [4, 3, 6, 2, 1, 1],
-
Calculate and :
-
Calculate and :
-
Solve for ():
-
Solve for and :
Result: (Repeating), (Missing).
Code Implementation (C++)
#include <vector>
using namespace std;
vector<int> findMissingRepeatingMath(vector<int>& arr) {
long long n = arr.size();
// Sum of N numbers and N^2 numbers
long long SN = (n * (n + 1)) / 2;
long long S2N = (n * (n + 1) * (2 * n + 1)) / 6;
// Calculate actual array sums
long long S = 0, S2 = 0;
for (int i = 0; i < n; i++) {
S += arr[i];
S2 += (long long)arr[i] * (long long)arr[i];
}
// Val1 = X - Y
long long val1 = S - SN;
// Val2 = X + Y
long long val2 = (S2 - S2N) / val1;
// Calculate X and Y
long long x = (val1 + val2) / 2;
long long y = x - val1;
return {(int)x, (int)y};
}
Complexity Analysis
- Time Complexity: — Single iteration over the array to compute and .
- Space Complexity: — Constant extra memory used.
7. Approach 4: Optimal Strategy 2 — Bit Manipulation / XOR ( Time, Space)
Core XOR Properties
- (Self-cancellation)
- (Identity)
- Commutative and Associative: Order of XOR operations does not matter.
Conceptual Mechanics
- Calculate Global XOR:
XOR all elements in
arrtogether with all numbers from to :
Because every standard number appears twice (once in arr and once in ), they cancel out to .
- appears 3 times (2 in array + 1 in range) leaves .
- appears 1 time (0 in array + 1 in range) leaves .
-
Identify Differentiating Bit: Since , must have at least one set bit (
1). A set bit at position implies that and have differentiating bits at index (one has0, the other has1). -
Bucket Categorization ("Zero-Club" vs. "One-Club"): Partition all array elements and numbers into two groups based on whether their -th bit is
0or1:- Zero-Bucket: All numbers with bit .
- One-Bucket: All numbers with bit .
XORing all elements inside the Zero-Bucket isolates one target number, and XORing all elements in the One-Bucket isolates the other!
-
Identify Which is Missing and Which is Repeating: After obtaining two isolated numbers and , make a quick pass through
arrto count occurrences of :- If appears twice in
arr(Repeating) and (Missing). - Otherwise (Repeating) and (Missing).
- If appears twice in
8. XOR Bucket Partition Walkthrough
Example Walkthrough: arr = [4, 3, 6, 2, 1, 1],
Array Elements : 4, 3, 6, 2, 1, 1
Range Elements : 1, 2, 3, 4, 5, 6
XR = (4 ^ 3 ^ 6 ^ 2 ^ 1 ^ 1) ^ (1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 6)
XR = 1 ^ 5 = (001)_2 ^ (101)_2 = (100)_2 = 4
- Position of set bit: Bit Index 2 (value
4in binary100).
Categorization into Buckets based on Bit Index 2
XOR Bucket Accumulation
- Zero-Bucket XOR:
- One-Bucket XOR:
Candidate values obtained: and .
Final Verification Pass
Traverse arr to count occurrences of :
- appears times in
arr. - Therefore: Repeating () = 1, Missing () = 5.
9. Complete C++ Implementation of Both Optimal Approaches
Code 1: Mathematical Solution
#include <iostream>
#include <vector>
using namespace std;
vector<int> findMissingRepeatingMath(const vector<int>& a) {
long long n = a.size();
long long SN = (n * (n + 1)) / 2;
long long S2N = (n * (n + 1) * (2 * n + 1)) / 6;
long long S = 0, S2 = 0;
for (int i = 0; i < n; i++) {
S += a[i];
S2 += (long long)a[i] * (long long)a[i];
}
long long val1 = S - SN; // X - Y
long long val2 = (S2 - S2N) / val1; // X + Y
long long x = (val1 + val2) / 2;
long long y = x - val1;
return {(int)x, (int)y};
}
Code 2: XOR Bit Manipulation Solution
#include <iostream>
#include <vector>
using namespace std;
vector<int> findMissingRepeatingXOR(const vector<int>& a) {
int n = a.size();
int xr = 0;
// Step 1: XOR all array elements and range elements 1..N
for (int i = 0; i < n; i++) {
xr ^= a[i];
xr ^= (i + 1);
}
// Step 2: Find differentiating bit (rightmost set bit)
// Bitwise trick: (xr & ~(xr - 1)) isolates the rightmost set bit
int bitNo = 0;
while (true) {
if ((xr & (1 << bitNo)) != 0) {
break;
}
bitNo++;
}
// Step 3: Group numbers into Zero-Bucket and One-Bucket
int zero = 0;
int one = 0;
// Separate array elements
for (int i = 0; i < n; i++) {
if ((a[i] & (1 << bitNo)) != 0) {
one ^= a[i];
} else {
zero ^= a[i];
}
}
// Separate range 1..N elements
for (int i = 1; i <= n; i++) {
if ((i & (1 << bitNo)) != 0) {
one ^= i;
} else {
zero ^= i;
}
}
// Step 4: Cross-check to confirm repeating and missing numbers
int cnt = 0;
for (int i = 0; i < n; i++) {
if (a[i] == zero) cnt++;
}
if (cnt == 2) {
return {zero, one}; // zero is repeating, one is missing
}
return {one, zero}; // one is repeating, zero is missing
}
10. Complexity Matrix & Trade-off Analysis
11. Summary and Key Takeaways
- Problem Definition: Find one repeating integer (count = 2) and one missing integer (count = 0) from an un-sorted array of size containing elements from to .
- Brute Force Baseline: Counting frequencies using nested loops yields an time and space complexity, which is impractical for large inputs ().
- Space-Time Trade-off (Hashing): Storing counts in an auxiliary array of size reduces time complexity to , but introduces auxiliary space overhead.
- Optimal Math Solution: Uses the difference of actual sums vs. expected sums () combined with actual sum of squares vs. expected sum of squares () to build solvable linear equations in time and space.
- Critical Pitfall in Math Approach: Calculating sum of squares () for causes standard 32-bit integer overflow. Data structures must be Typecast to 64-bit integers (
long long). - Optimal Bit Manipulation Solution: XORing all array values with numbers eliminates paired identical values, resulting in .
- Differentiating Bit Concept: Because , contains at least one set bit (
1). Partitioning elements based on this bit isolates and into separate buckets. - Overflow Safety: The XOR method processes bits directly without accumulating massive sum totals, completely eliminating integer overflow risks in any language.
- Final Verification Step: Both mathematical and bit manipulation approaches compute two unique candidate values. A single linear check is required to definitively assign which candidate is repeating and which is missing.