Missing Number
Given an array nums containing n distinct numbers taken from the range 0, 1, 2, ..., n, find the one number in that range that is missing from the array.
Examples:
Example 1:
Input: nums = [3, 0, 1]
Output: 2
Explanation: n = 3 since there are 3 numbers, so the range is [0,3]. 2 is the missing number.
Example 2:
Input: nums = [0, 1]
Output: 2
Explanation: n = 2 since there are 2 numbers, so the range is [0,2]. 2 is the missing number.
Example 3:
Input: nums = [9, 6, 4, 2, 3, 5, 7, 0, 1]
Output: 8
Explanation: n = 9 since there are 9 numbers, so the range is [0,9]. 8 is the missing number.
Example 4:
Input: nums = [0]
Output: 1
Explanation: n = 1 since there is 1 number, so the range is [0,1]. 1 is the missing number.
Constraints:
n == nums.length1 <= n <= 1040 <= nums[i] <= n- All the numbers of
numsare unique.
Function Signature (Python):
from typing import List
class Solution:
def missingNumber(self, nums: List[int]) -> int:
# Your code here
pass
Related Python Concepts
Hint
Consider what properties the complete sequence 0, 1, ..., n has, and how the given array `nums` (which is missing one element from this sequence) differs.
- Sum Difference: If you knew the sum of all numbers from
0ton, and you knew the sum of numbers in the given arraynums, how could you find the missing number? (Gauss's summation formula might be helpful: sum of first k integers isk*(k+1)/2). - XOR Property: Remember that
x ^ x = 0andx ^ 0 = x. Also, XOR is commutative and associative. Can you XOR all numbers from0ton, and then XOR this result with the XOR sum of all numbers innums? What would be left? - Ordered Sequence: If the numbers were sorted, you'd expect
nums[i]to be equal toi. Where would this pattern break if a number is missing? - Presence Check: Could you quickly check for the presence of each number from
0tonusing a data structure optimized for lookups?
Solution Explanation & Interview Strategy
The Goal: Imagine you have a set of numbers that should be 0, 1, 2, ..., n (e.g., if n=3, the set is 0, 1, 2, 3). You're given an array that contains all of these numbers except one. Our job is to find that missing one.
For instance, if n=3 and you're given nums = [3, 0, 1], the complete set should be [0, 1, 2, 3]. Comparing them, we see 2 is missing.
Approach 1: Summation (Gauss's Formula)
The sum of the first k non-negative integers (0 to k-1) is (k-1)*k/2. In our case, the numbers are from 0 to n (inclusive), where n is also the length of the input array nums. So, the complete sequence has n+1 numbers. The largest number in this complete sequence is n. The sum of integers from 0 to n is given by the formula n * (n + 1) / 2. We can calculate this expected sum. Then, we calculate the actual sum of elements in the given nums array. The difference between the expected sum and the actual sum will be the missing number.
from typing import List
class Solution:
def missingNumber_summation(self, nums: List[int]) -> int:
n_val = len(nums) # This is the 'n' from the range 0...n
# Calculate the expected sum of numbers from 0 to n_val
expected_sum = n_val * (n_val + 1) // 2
# Calculate the actual sum of numbers in the array
actual_sum = sum(nums)
return expected_sum - actual_sum
# Example Usage:
# sol = Solution()
# print(sol.missingNumber_summation([3, 0, 1])) # Output: 2
# print(sol.missingNumber_summation([0, 1])) # Output: 2
n_val = len(nums) = 3. The numbers should be from the range[0, 1, 2, 3].expected_sum = 3 * (3 + 1) / 2 = 3 * 4 / 2 = 6.actual_sum = sum([3, 0, 1]) = 4.- Missing number =
expected_sum - actual_sum = 6 - 4 = 2.
Complexity Analysis:
Time Complexity: O(N), where N is the number of elements in nums. This is dominated by the sum(nums) operation.
Space Complexity: O(1), as we only use a few variables for sums.
Approach 2: Bitwise XOR
The XOR operation has useful properties: x ^ x = 0 and x ^ 0 = x. Also, XOR is commutative and associative. We can XOR all numbers from 0 to n (where n = len(nums)). Let this be xor_all. Then, we XOR all numbers in the input array nums. Let this be xor_nums. The missing number will be xor_all ^ xor_nums. This is because all numbers present in both sequences will cancel each other out (x ^ x = 0), leaving only the missing number XORed with 0, which is the missing number itself.
from typing import List
class Solution:
def missingNumber_xor(self, nums: List[int]) -> int:
n_val = len(nums)
missing = n_val # Start with n, as it's part of the 0..n range
for i in range(n_val):
missing ^= i # XOR with the expected number at this index (0 to n-1)
missing ^= nums[i] # XOR with the actual number in the array
return missing
# Example Usage:
# sol = Solution()
# print(sol.missingNumber_xor([3, 0, 1])) # Output: 2
n_val = 3.missing = 3.i = 0,nums[0] = 3:missing = missing ^ 0 = 3 ^ 0 = 3missing = missing ^ nums[0] = 3 ^ 3 = 0
i = 1,nums[1] = 0:missing = missing ^ 1 = 0 ^ 1 = 1missing = missing ^ nums[1] = 1 ^ 0 = 1
i = 2,nums[2] = 1:missing = missing ^ 2 = 1 ^ 2 = 3(since 01 ^ 10 = 11)missing = missing ^ nums[2] = 3 ^ 1 = 2(since 11 ^ 01 = 10)
- Loop ends. Return
missing(which is 2).
Essentially, we are calculating (0^1^...^n) ^ (nums[0]^nums[1]^...^nums[n-1]).
Complexity Analysis:
Time Complexity: O(N), for iterating through the array once.
Space Complexity: O(1), using only a few variables.
Approach 3: Sorting
If we sort the array nums, the elements should ideally match their indices (i.e., nums[i] == i). If we find an index i where nums[i] != i, then i is the missing number. If the entire array matches its indices up to n-1, then the missing number must be n.
from typing import List
class Solution:
def missingNumber_sorting(self, nums: List[int]) -> int:
nums.sort() # Sort the array in-place
n_val = len(nums)
# Check if elements match their indices
for i in range(n_val):
if nums[i] != i:
return i
# If all elements from 0 to n-1 are present, then n is the missing number
return n_val
# Example Usage:
# sol = Solution()
# print(sol.missingNumber_sorting([3, 0, 1])) # Output: 2
# print(sol.missingNumber_sorting([0])) # Output: 1
Complexity Analysis:
Time Complexity: O(N log N), dominated by the sorting step. The subsequent loop is O(N).
Space Complexity: O(1) or O(N) depending on the sort implementation. Python's Timsort (used in sort()) takes O(N) space in the worst case (O(log N) for typical cases). If an in-place sort like Heapsort was used, it would be O(1).
Approach 4: Using a Hash Set
We can insert all numbers from nums into a hash set for O(1) average time lookups. Then, iterate from 0 to n (inclusive) and check if each number is present in the hash set. The first number not found is the missing one.
from typing import List
class Solution:
def missingNumber_hash_set(self, nums: List[int]) -> int:
num_set = set(nums)
n_val = len(nums)
for number in range(n_val + 1): # Check numbers from 0 to n_val
if number not in num_set:
return number
return -1 # Should not be reached given problem constraints
Complexity Analysis:
Time Complexity: O(N). Building the set takes O(N). The loop runs N+1 times, with each set lookup being O(1) on average.
Space Complexity: O(N) for storing the numbers in the hash set.
Key Takeaways for Interviews:
- Understand the Input: The key is that
numscontainsndistinct numbers from the range[0, n]. This means exactly one number is missing. - Mathematical Insight (Summation): The summation approach is elegant and efficient (O(N) time, O(1) space). It's a good one to lead with if you see it.
- Bitwise Manipulation (XOR): The XOR solution is also O(N) time and O(1) space, and showcases a different kind of cleverness. Be prepared to explain why XOR works.
- Common Data Structure Solutions:
- Sorting (O(N log N) time) is a valid approach but less optimal than summation or XOR.
- Hash Set (O(N) time, O(N) space) is also intuitive and effective.
- Discuss Trade-offs: Be ready to compare the solutions in terms of their time and space complexities. For example, Summation and XOR are optimal in both, while Sorting is slower and Hash Set uses more space.