Arrays Masterclass: Missing Number, Max Consecutive Ones, and Single Number (Arrays Part-3)
This lecture focuses on three core array manipulation problems frequently asked in technical coding interviews: Finding the Missing Number in an Array (1 to ), Maximum Consecutive 1s, and Finding the Element That Appears Once (Single Number). Beyond solving these specific problems, the module demonstrates how to drive technical interviews by evolving code logically from Brute Force Better (Hashing) Optimal (Mathematical / Bit Manipulation) approaches.
1. Driving the Interview: The Brute-to-Optimal Mindset
When solving Data Structures and Algorithms (DSA) problems during technical interviews, jumping directly to the optimal solution can hurt your evaluation. Interviewers evaluate your thought process, edge-case awareness, and system optimization skills.
Interview Rubric Note: Showing why an optimal solution is chosen (e.g., explaining why XOR outperforms Summation due to integer overflow prevention) separates high-performing candidates from those who simply memorize code.
2. Problem 1 — Find Missing Number: Problem Statement & Brute Force Approach
Problem Statement
Given an integer and an array containing distinct numbers selected from the range , find the single number that is missing from the array.
- Example:
,
Output: (since numbers from to are expected, and is absent).
Brute Force Approach: Nested Linear Search
Check every integer from to to see if it exists in the array using a linear search for each number.
Algorithm Steps
- Outer loop runs from to .
- Inner loop iterates over the array to search for .
- If is found, set a
flag = 1and break out of the inner loop. - If after checking the entire array
flagremains0, then is the missing number.
int missingNumberBrute(vector<int>& a, int N) {
for (int i = 1; i <= N; i++) {
int flag = 0;
for (int j = 0; j < N - 1; j++) {
if (a[j] == i) {
flag = 1;
break;
}
}
if (flag == 0) return i;
}
return -1;
}
Complexity Analysis
- Time Complexity:
In the worst case (e.g., is missing at the end), the outer loop runs times and the inner loop runs up to times. - Space Complexity:
No additional dynamic memory allocated.
3. Problem 1 — Better Approach via Hashing
To avoid the quadratic runtime of nested searching, trade space for time by caching frequency counts in a Hash Array.
Hashing Strategy
Create an array of size (initialized to 0). Iterate through the input array and set hash[a[i]] = 1. Then, scan the hash array from index to ; the index containing 0 is the missing element.
int missingNumberBetter(vector<int>& a, int N) {
vector<int> hash(N + 1, 0);
// Step 1: Store frequencies
for (int i = 0; i < N - 1; i++) {
hash[a[i]] = 1;
}
// Step 2: Find the zero frequency index
for (int i = 1; i <= N; i++) {
if (hash[i] == 0) {
return i;
}
}
return -1;
}
Input Array: [1, 2, 4, 5], N = 5
Hash Array Initialization (Size 6):
Index: [0] [1] [2] [3] [4] [5]
Val: 0 0 0 0 0 0
After Frequency Pass:
Index: [0] [1] [2] [3] [4] [5]
Val: 0 1 1 0 1 1
^
Missing element = 3
Complexity Analysis
- Time Complexity:
One pass of size to populate hash + one pass of size to inspect. - Space Complexity:
Requires extra array of size .
4. Problem 1 — Optimal Solution 1: Summation Formula & Integer Overflow Risk
We can eliminate the space overhead using the mathematical sum of the first natural numbers:
Subtracting the actual sum of elements in the array () from yields the missing number.
int missingNumberSum(vector<int>& a, int N) {
// Calculate theoretical sum
long long sumN = ((long long)N * (N + 1)) / 2;
// Calculate actual array sum
long long S2 = 0;
for (int i = 0; i < N - 1; i++) {
S2 += a[i];
}
return sumN - S2;
}
Warning: Production & Interview Pitfall (Integer Overflow)
If , , which exceeds the standard 32-bit signed integer maximum limit (). You must cast the sum to a 64-bit data type (long longin C++,longin Java) to prevent overflow bugs.
5. Problem 1 — Optimal Solution 2: XOR Bit Manipulation (The Supreme Approach)
To optimize space without risking integer overflow, use the bitwise XOR () operator.
Fundamental XOR Properties
- Self-Cancellation: (XORing identical numbers yields zero).
- Identity: (XORing any number with zero returns the original number).
- Commutativity & Associativity: Order of operations does not alter the result.
Mental Model & Mechanics
If you compute the XOR of all numbers from () and XOR it with all elements present in the array (), every number present in both sets cancels itself out, leaving only the missing number.
Loop Unification Optimization (Single-Pass Execution)
Instead of running two separate loops to calculate and , combine them inside a single loop:
int missingNumberXOR(vector<int>& a, int N) {
int xor1 = 0;
int xor2 = 0;
for (int i = 0; i < N - 1; i++) {
xor2 = xor2 ^ a[i]; // Array element XOR
xor1 = xor1 ^ (i + 1); // Range [1 to N-1] XOR
}
xor1 = xor1 ^ N; // Incorporate N into the range XOR
return xor1 ^ xor2; // Missing number isolated
}
6. Problem 1 — Code Implementation & Performance Synthesis
Summation vs. XOR: Which is Better?
7. Problem 2 — Max Consecutive Ones: Problem Analysis & Single-Pass State Tracking
Problem Statement
Given a binary array consisting of only 0s and 1s, return the maximum number of consecutive 1s present in the array.
- Example:
Output:
Algorithm & State Tracking
Maintain two scalar counter variables during a single iteration:
cnt: Tracks current contiguous sequence of1s.maxi: Stores global peak count achieved so far.
Array Iteration Trace:
Index: 0 1 2 3 4 5 6 7 8
Val: [1, 1, 0, 1, 1, 1, 0, 1, 1]
cnt: 1 2 0 1 2 3 0 1 2
maxi: 1 2 2 2 2 3 3 3 3
^ ^
Reset cnt Max updated
Complete Code (C++)
int findMaxConsecutiveOnes(vector<int>& nums) {
int maxi = 0;
int cnt = 0;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] == 1) {
cnt++;
maxi = max(maxi, cnt);
} else {
cnt = 0; // Reset counter on encountering 0
}
}
return maxi;
}
Complexity Analysis
- Time Complexity: (Single traversal).
- Space Complexity: (Only two local variables used).
8. Problem 3 — Find the Element That Appears Once: Problem Statement & Brute Force
Problem Statement
Given a non-empty array of integers where every element appears twice except for one, find that single unique element.
- Example:
Output:
Brute Force Approach: Linear Frequency Counting
For each element in the array, run an inner loop over the entire array to count its total occurrences.
int getSingleElementBrute(vector<int>& arr) {
int n = arr.size();
for (int i = 0; i < n; i++) {
int num = arr[i];
int count = 0;
for (int j = 0; j < n; j++) {
if (arr[j] == num) {
count++;
}
}
if (count == 1) return num;
}
return -1;
}
Complexity Analysis
- Time Complexity:
- Space Complexity:
9. Problem 3 — Better Approach: Array Hashing vs. Hash Maps (Trade-offs & Edge Cases)
Alternative 1: Direct Array Hashing
Determine the maximum element (), instantiate a hash array of size , and populate occurrences.
int getSingleElementHashArray(vector<int>& arr) {
int n = arr.size();
int maxi = arr[0];
for (int i = 0; i < n; i++) maxi = max(maxi, arr[i]);
vector<int> hash(maxi + 1, 0);
for (int i = 0; i < n; i++) hash[arr[i]]++;
for (int i = 0; i < n; i++) {
if (hash[arr[i]] == 1) return arr[i];
}
return -1;
}
Limitations of Array Hashing:
- Negative Integers: Array indices cannot be negative (e.g.,
arr[i] = -5breaks index access).- Memory Explosion: If maximum element is , declaring an array of size causes a Memory Limit Exceeded (MLE) crash.
Alternative 2: Hash Map (std::map / unordered_map)
To handle negative numbers and large integer values efficiently, map keys to their frequency counts.
int getSingleElementMap(vector<int>& arr) {
int n = arr.size();
// Key: Element, Value: Frequency
unordered_map<int, int> mpp;
for (int i = 0; i < n; i++) {
mpp[arr[i]]++;
}
// Find key with frequency 1
for (auto it : mpp) {
if (it.second == 1) {
return it.first;
}
}
return -1;
}
Hash Map Complexity Breakdown
Note: because almost all elements appear twice, making map size roughly half of .
10. Problem 3 — Optimal Solution: XOR Self-Cancellation Property
By using bitwise XOR, we achieve runtime with space, bypassing hash collision risks entirely.
Conceptual Workflow
Since XOR is associative and commutative:
All paired elements cancel each other out (), leaving only the unique element ().
Input: [4, 1, 2, 1, 2]
Bitwise Operation Sequence:
4 ^ 1 ^ 2 ^ 1 ^ 2
= 4 ^ (1 ^ 1) ^ (2 ^ 2)
= 4 ^ 0 ^ 0
= 4
Complete Code (C++)
int getSingleElementOptimal(vector<int>& arr) {
int xorr = 0;
for (int i = 0; i < arr.size(); i++) {
xorr = xorr ^ arr[i];
}
return xorr;
}
Complexity Analysis
- Time Complexity: (Single linear sweep).
- Space Complexity: (Single register state).
11. Comparative Analysis & Algorithm Selection Matrix
Here is an overview comparing the approaches across all three problems discussed in this masterclass:
12. Summary and Key Takeaways
- Structured Interview Delivery: Always lead with the Brute Force approach to establish problem comprehension, highlight its algorithmic bottlenecks, and then systematically progress to optimal solutions.
- Summation vs. XOR for Missing Numbers: While Summation yields time and space, XOR is superior because it avoids 64-bit integer overflow issues when is large ().
- Single-Pass XOR Unification: In the Missing Number problem, combining the range XOR () and the array element XOR inside a single loop eliminates redundant traversal passes.
- Consecutive Counting Pattern: Track contiguous binary states by incrementing a local counter on target hits (
1) and instantly resetting it to zero when interrupted by non-target elements (0). - Array Hashing Constraints: Frequency arrays are limited by non-negative domain inputs and bounded integer ranges.
- XOR Self-Cancellation: Use the bitwise property () to isolate single unique elements from paired duplicates in time and space.