1060. Missing Element in Sorted Array 🔒
Problem Description
You are given an integer array nums
that is sorted in ascending order, where all elements are unique. You're also given an integer k
.
The task is to find the k
th missing number in the sequence, starting from the leftmost (first) element of the array.
A "missing number" is any integer that should appear in the continuous sequence starting from nums[0]
but is not present in the array. For example:
- If
nums = [4, 7, 9, 10]
andk = 1
, the first missing number starting from 4 would be 5 (since 5 is not in the array). - If
k = 2
, the second missing number would be 6. - If
k = 3
, the third missing number would be 8.
The solution uses binary search to efficiently find the k
th missing number. The helper function missing(i)
calculates how many numbers are missing up to index i
by using the formula: nums[i] - nums[0] - i
. This works because in a continuous sequence with no missing numbers, the element at index i
would be nums[0] + i
.
The algorithm first checks if k
is greater than the total number of missing elements in the array range. If so, it calculates the answer by extending beyond the last element. Otherwise, it uses binary search to find the position where exactly k
missing numbers have occurred, then calculates the k
th missing number based on that position.
Intuition
The key insight is recognizing that we can calculate how many numbers are missing up to any position in the array without actually listing them out.
Think about it this way: if we have a perfectly continuous sequence starting from nums[0]
, the element at index i
should be nums[0] + i
. For example, if nums[0] = 4
, then ideally we'd have [4, 5, 6, 7, ...]
. But in reality, we might have [4, 7, 9, ...]
where some numbers are skipped.
The difference between what we actually have (nums[i]
) and what we should have (nums[0] + i
) tells us exactly how many numbers are missing up to that point. This gives us the formula: missing(i) = nums[i] - nums[0] - i
.
Once we can efficiently count missing numbers at any position, finding the k
th missing number becomes a search problem. We need to find where in the array the count of missing numbers transitions from less than k
to at least k
.
Since the array is sorted and the count of missing numbers is monotonically increasing (we can only have more missing numbers as we go further, never fewer), we can use binary search. We're essentially searching for the leftmost position where we have at least k
missing numbers.
The edge case is when k
is larger than all the missing numbers within the array range. In this case, the k
th missing number must be beyond the last element of the array, and we can calculate it directly by extending from the last element.
Learn more about Binary Search patterns.
Solution Approach
The solution implements a binary search algorithm with a helper function to efficiently find the k
th missing number.
Helper Function:
The missing(i)
function calculates the count of missing numbers up to index i
:
- Formula:
nums[i] - nums[0] - i
- This represents the difference between the actual value at index
i
and what it should be in a continuous sequence
Main Algorithm Steps:
-
Check if k exceeds array bounds:
- Calculate total missing numbers in the array:
missing(n - 1)
- If
k > missing(n - 1)
, the answer lies beyond the array - Return:
nums[n - 1] + k - missing(n - 1)
- This adds the remaining missing numbers to the last element
- Calculate total missing numbers in the array:
-
Binary Search Implementation:
- Initialize pointers:
l = 0
,r = n - 1
- Search for the leftmost position where
missing(mid) >= k
- In each iteration:
- Calculate
mid = (l + r) >> 1
(bit shift for division by 2) - If
missing(mid) >= k
: move right pointer tomid
- Otherwise: move left pointer to
mid + 1
- Calculate
- Initialize pointers:
-
Calculate the Result:
- After binary search,
l
points to the first index where we have at leastk
missing numbers - The
k
th missing number is between indicesl-1
andl
- Return:
nums[l - 1] + k - missing(l - 1)
- This formula adds the remaining missing numbers needed to reach
k
from positionl-1
- After binary search,
Time Complexity: O(log n)
due to binary search
Space Complexity: O(1)
as we only use a few variables
The elegance of this solution lies in avoiding the enumeration of all missing numbers and instead using mathematical relationships to directly compute the answer.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with nums = [4, 7, 9, 10]
and k = 3
.
Step 1: Calculate missing numbers at each index
Using the formula missing(i) = nums[i] - nums[0] - i
:
- Index 0:
missing(0) = 4 - 4 - 0 = 0
(no missing numbers before 4) - Index 1:
missing(1) = 7 - 4 - 1 = 2
(numbers 5 and 6 are missing) - Index 2:
missing(2) = 9 - 4 - 2 = 3
(numbers 5, 6, and 8 are missing) - Index 3:
missing(3) = 10 - 4 - 3 = 3
(same 3 missing numbers)
Step 2: Check if k exceeds array bounds
- Total missing in array:
missing(3) = 3
- Since
k = 3
is not greater than 3, we proceed with binary search
Step 3: Binary Search
Looking for the leftmost position where missing(mid) >= k
:
Iteration 1:
l = 0, r = 3
mid = (0 + 3) >> 1 = 1
missing(1) = 2
, which is less thank = 3
- Move left pointer:
l = 2
Iteration 2:
l = 2, r = 3
mid = (2 + 3) >> 1 = 2
missing(2) = 3
, which equalsk = 3
- Move right pointer:
r = 2
Iteration 3:
l = 2, r = 2
, loop ends
Step 4: Calculate the result
l = 2
, so we look at positionl - 1 = 1
missing(1) = 2
(we have 2 missing numbers by index 1)- We need
k - missing(1) = 3 - 2 = 1
more missing number - Result:
nums[1] + (k - missing(1)) = 7 + 1 = 8
Verification: The missing numbers in order are: 5, 6, 8. The 3rd missing number is indeed 8.
Solution Implementation
1class Solution:
2 def missingElement(self, nums: List[int], k: int) -> int:
3 """
4 Find the k-th missing element in a sorted array.
5
6 Args:
7 nums: A sorted array of integers
8 k: The k-th missing number to find
9
10 Returns:
11 The k-th missing integer
12 """
13
14 def count_missing_before_index(index: int) -> int:
15 """
16 Calculate how many numbers are missing before nums[index].
17
18 The missing count is the difference between:
19 - The actual range covered (nums[index] - nums[0])
20 - The number of elements present (index)
21 """
22 return nums[index] - nums[0] - index
23
24 n = len(nums)
25
26 # Check if k-th missing element is beyond the array's last element
27 total_missing_in_range = count_missing_before_index(n - 1)
28 if k > total_missing_in_range:
29 # The k-th missing element is after the last element
30 # Add the remaining missing count to the last element
31 return nums[n - 1] + k - total_missing_in_range
32
33 # Binary search to find the position where k-th missing element should be
34 left, right = 0, n - 1
35
36 while left < right:
37 mid = (left + right) // 2
38
39 if count_missing_before_index(mid) >= k:
40 # k-th missing element is before or at mid
41 right = mid
42 else:
43 # k-th missing element is after mid
44 left = mid + 1
45
46 # The k-th missing element is between nums[left-1] and nums[left]
47 # Calculate its exact value by adding the remaining count to nums[left-1]
48 return nums[left - 1] + k - count_missing_before_index(left - 1)
49
1class Solution {
2 /**
3 * Find the k-th missing element in a sorted array.
4 * The k-th missing element is the k-th positive integer that is missing from the array.
5 *
6 * @param nums A sorted array of distinct integers
7 * @param k The k-th missing element to find (1-indexed)
8 * @return The k-th missing element
9 */
10 public int missingElement(int[] nums, int k) {
11 int n = nums.length;
12
13 // Check if k-th missing element is beyond the last element of array
14 // If so, calculate directly from the last element
15 if (k > countMissingBeforeIndex(nums, n - 1)) {
16 return nums[n - 1] + k - countMissingBeforeIndex(nums, n - 1);
17 }
18
19 // Binary search to find the position where k-th missing element should be
20 int left = 0;
21 int right = n - 1;
22
23 while (left < right) {
24 int mid = (left + right) >> 1; // Equivalent to (left + right) / 2
25
26 // If number of missing elements before mid is >= k,
27 // the k-th missing element is in the left half (including mid)
28 if (countMissingBeforeIndex(nums, mid) >= k) {
29 right = mid;
30 } else {
31 // Otherwise, search in the right half
32 left = mid + 1;
33 }
34 }
35
36 // Calculate the k-th missing element based on the element before left position
37 return nums[left - 1] + k - countMissingBeforeIndex(nums, left - 1);
38 }
39
40 /**
41 * Calculate the number of missing elements before index i (inclusive).
42 * Missing elements are the positive integers that should exist between nums[0] and nums[i]
43 * but are not present in the array.
44 *
45 * @param nums The sorted array
46 * @param i The index to check up to (inclusive)
47 * @return The count of missing elements before index i
48 */
49 private int countMissingBeforeIndex(int[] nums, int i) {
50 // Total range from nums[0] to nums[i] is (nums[i] - nums[0])
51 // Actual elements present in this range is (i + 1) including both endpoints
52 // So missing elements = total range - actual elements present
53 return nums[i] - nums[0] - i;
54 }
55}
56
1class Solution {
2public:
3 int missingElement(vector<int>& nums, int k) {
4 // Lambda function to calculate how many numbers are missing before index i
5 // Formula: (actual value at i) - (expected value if no gaps) = missing count
6 // Expected value at index i would be nums[0] + i if there were no gaps
7 auto countMissingBeforeIndex = [&](int index) {
8 return nums[index] - nums[0] - index;
9 };
10
11 int arraySize = nums.size();
12
13 // Check if the k-th missing number is beyond the array's range
14 // If so, calculate it directly from the last element
15 if (k > countMissingBeforeIndex(arraySize - 1)) {
16 return nums[arraySize - 1] + k - countMissingBeforeIndex(arraySize - 1);
17 }
18
19 // Binary search to find the leftmost index where
20 // the count of missing numbers before it is >= k
21 int left = 0;
22 int right = arraySize - 1;
23
24 while (left < right) {
25 int mid = (left + right) >> 1; // Equivalent to (left + right) / 2
26
27 if (countMissingBeforeIndex(mid) >= k) {
28 // k-th missing number is at or before mid
29 right = mid;
30 } else {
31 // k-th missing number is after mid
32 left = mid + 1;
33 }
34 }
35
36 // The k-th missing number is between nums[left-1] and nums[left]
37 // Calculate it based on nums[left-1] plus the remaining missing numbers needed
38 return nums[left - 1] + k - countMissingBeforeIndex(left - 1);
39 }
40};
41
1function missingElement(nums: number[], k: number): number {
2 // Helper function to calculate how many numbers are missing before index i
3 // Formula: (actual value at i) - (expected value if no gaps) = missing count
4 // Expected value at index i would be nums[0] + i if there were no gaps
5 const countMissingBeforeIndex = (index: number): number => {
6 return nums[index] - nums[0] - index;
7 };
8
9 const arraySize = nums.length;
10
11 // Check if the k-th missing number is beyond the array's range
12 // If so, calculate it directly from the last element
13 if (k > countMissingBeforeIndex(arraySize - 1)) {
14 return nums[arraySize - 1] + k - countMissingBeforeIndex(arraySize - 1);
15 }
16
17 // Binary search to find the leftmost index where
18 // the count of missing numbers before it is >= k
19 let left = 0;
20 let right = arraySize - 1;
21
22 while (left < right) {
23 // Calculate middle index using bit shift (equivalent to Math.floor((left + right) / 2))
24 const mid = (left + right) >> 1;
25
26 if (countMissingBeforeIndex(mid) >= k) {
27 // k-th missing number is at or before mid
28 right = mid;
29 } else {
30 // k-th missing number is after mid
31 left = mid + 1;
32 }
33 }
34
35 // The k-th missing number is between nums[left-1] and nums[left]
36 // Calculate it based on nums[left-1] plus the remaining missing numbers needed
37 return nums[left - 1] + k - countMissingBeforeIndex(left - 1);
38}
39
Time and Space Complexity
Time Complexity: O(log n)
The algorithm uses binary search to find the position where the k-th missing element would be. The missing(i)
helper function calculates how many numbers are missing up to index i
in constant time O(1)
. The binary search loop runs for O(log n)
iterations where n
is the length of the input array. Each iteration performs constant time operations including calling missing()
, comparisons, and index calculations. Therefore, the overall time complexity is O(log n)
.
Space Complexity: O(1)
The algorithm uses only a constant amount of extra space. The variables l
, r
, mid
, and n
are all integers that occupy constant space. The helper function missing(i)
doesn't create any additional data structures and only performs arithmetic operations. No recursive calls are made, so there's no additional stack space usage beyond the function call itself. Therefore, the space complexity is O(1)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Off-by-One Error in Binary Search Boundary
A frequent mistake is incorrectly handling the binary search boundaries, particularly when determining whether to include mid
in the next search range.
Pitfall Example:
# Incorrect: Using left = mid instead of left = mid + 1 while left < right: mid = (left + right) // 2 if count_missing_before_index(mid) >= k: right = mid else: left = mid # Wrong! Can cause infinite loop
Why it fails: When left
and right
differ by 1, mid
equals left
, and if the condition fails, left
never advances, causing an infinite loop.
Solution: Always use left = mid + 1
when the condition fails to ensure progression.
2. Incorrect Final Calculation Formula
Another common error is using the wrong index or formula when calculating the final result.
Pitfall Example:
# Incorrect: Using nums[left] instead of nums[left - 1] return nums[left] + k - count_missing_before_index(left)
Why it fails: After binary search, left
points to the first position where we have at least k
missing numbers. The k-th missing number lies between nums[left-1]
and nums[left]
, not after nums[left]
.
Solution: Use nums[left - 1] + k - count_missing_before_index(left - 1)
to correctly calculate from the previous position.
3. Not Handling Edge Case When k=1 and left=0
When the first missing number occurs before the first element, accessing nums[left - 1]
causes an index error.
Pitfall Example:
# If nums = [5, 7, 9] and k = 1, the first missing is before index 0 # After binary search, left = 0 return nums[left - 1] + k - count_missing_before_index(left - 1) # IndexError!
Solution: Add a special check for when left == 0
:
if left == 0: # All k missing numbers come before the first element return nums[0] - k else: return nums[left - 1] + k - count_missing_before_index(left - 1)
4. Misunderstanding the Missing Count Formula
Developers sometimes incorrectly calculate the missing count by forgetting to subtract the starting position.
Pitfall Example:
# Incorrect: Not accounting for the starting position
def count_missing_before_index(index):
return nums[index] - index # Wrong! Assumes sequence starts at 0
Why it fails: If nums = [4, 7, 9]
, this would incorrectly calculate missing(0) = 4, when actually no numbers are missing before index 0 (since we start counting from 4).
Solution: Always use nums[index] - nums[0] - index
to correctly count missing numbers relative to the starting element.
What does the following code do?
1def f(arr1, arr2):
2 i, j = 0, 0
3 new_arr = []
4 while i < len(arr1) and j < len(arr2):
5 if arr1[i] < arr2[j]:
6 new_arr.append(arr1[i])
7 i += 1
8 else:
9 new_arr.append(arr2[j])
10 j += 1
11 new_arr.extend(arr1[i:])
12 new_arr.extend(arr2[j:])
13 return new_arr
14
1public static List<Integer> f(int[] arr1, int[] arr2) {
2 int i = 0, j = 0;
3 List<Integer> newArr = new ArrayList<>();
4
5 while (i < arr1.length && j < arr2.length) {
6 if (arr1[i] < arr2[j]) {
7 newArr.add(arr1[i]);
8 i++;
9 } else {
10 newArr.add(arr2[j]);
11 j++;
12 }
13 }
14
15 while (i < arr1.length) {
16 newArr.add(arr1[i]);
17 i++;
18 }
19
20 while (j < arr2.length) {
21 newArr.add(arr2[j]);
22 j++;
23 }
24
25 return newArr;
26}
27
1function f(arr1, arr2) {
2 let i = 0, j = 0;
3 let newArr = [];
4
5 while (i < arr1.length && j < arr2.length) {
6 if (arr1[i] < arr2[j]) {
7 newArr.push(arr1[i]);
8 i++;
9 } else {
10 newArr.push(arr2[j]);
11 j++;
12 }
13 }
14
15 while (i < arr1.length) {
16 newArr.push(arr1[i]);
17 i++;
18 }
19
20 while (j < arr2.length) {
21 newArr.push(arr2[j]);
22 j++;
23 }
24
25 return newArr;
26}
27
Recommended Readings
Binary Search Speedrun For each of the Speedrun questions you will be given a binary search related problem and a corresponding multiple choice question The multiple choice questions are related to the techniques and template s introduced in the binary search section It's recommended that you have gone through at
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!