1539. Kth Missing Positive Number
Problem Description
You are given an array arr containing positive integers that are sorted in strictly increasing order, and an integer k.
Your task is to find the kth positive integer that is missing from the array.
For example:
- If
arr = [2, 3, 4, 7, 11]andk = 5, the missing positive integers are[1, 5, 6, 8, 9, ...]. The 5th missing positive integer is9. - If
arr = [1, 2, 3, 4]andk = 2, the missing positive integers are[5, 6, 7, 8, ...]. The 2nd missing positive integer is6.
The solution uses binary search to efficiently find the answer. The key insight is that for any index i in the array, the number of missing positive integers before arr[i] can be calculated as arr[i] - i - 1 (since if no numbers were missing, arr[i] would equal i + 1).
The algorithm:
- First checks if the answer is before the first element (when
arr[0] > k) - Uses binary search to find the position where exactly
kmissing numbers have occurred - Calculates the final answer based on the last element before the position found and adjusts for the remaining missing numbers needed
Intuition
The key observation is that if no positive integers were missing from the array, then arr[0] would be 1, arr[1] would be 2, and so on. In general, arr[i] would equal i + 1.
Since the array might have missing positive integers, we can calculate how many positive integers are missing before any element arr[i] using the formula: arr[i] - (i + 1) or simplified as arr[i] - i - 1.
For example, if arr[2] = 7 (at index 2), then ideally it should have been 3 if no numbers were missing. So the count of missing numbers before 7 is 7 - 2 - 1 = 4, which means the missing numbers are [1, 2, 4, 5] (assuming previous elements are 3 and 6).
This count of missing numbers increases as we move through the array. Since the array is sorted, we can use binary search to find the position where we've seen just enough missing numbers.
We're looking for the rightmost position where the count of missing numbers is less than k, or equivalently, the leftmost position where the count is at least k. Once we find this position, we know that:
- If we're at position
left - 1, there are fewer thankmissing numbers - The
kth missing number lies somewhere afterarr[left - 1]
To find the exact value, we start from arr[left - 1] and add the remaining count needed. The remaining count is k minus the number of missing integers before arr[left - 1], which gives us: arr[left - 1] + (k - (arr[left - 1] - (left - 1) - 1)).
The special case at the beginning (if arr[0] > k) handles when the kth missing number appears before the first element of the array. For instance, if arr = [5, 6, 7] and k = 2, the missing numbers [1, 2, 3, 4] all come before arr[0], so the answer is simply k = 2.
Learn more about Binary Search patterns.
Solution Implementation
1class Solution:
2 def findKthPositive(self, arr: List[int], k: int) -> int:
3 # Edge case: if arr[0] > k, all k missing numbers come before the array
4 if arr[0] > k:
5 return k
6
7 # Binary search using the standard template
8 # Feasible function: arr[mid] - mid - 1 >= k (at least k numbers missing before mid)
9 left, right = 0, len(arr) - 1
10 first_true_index = -1
11
12 while left <= right:
13 mid = (left + right) // 2
14
15 # Calculate how many positive integers are missing before arr[mid]
16 missing_count = arr[mid] - mid - 1
17
18 if missing_count >= k:
19 # Feasible: at least k missing numbers before this position
20 first_true_index = mid
21 right = mid - 1
22 else:
23 # Not feasible: need to search further right
24 left = mid + 1
25
26 # Calculate the kth missing number
27 if first_true_index == -1:
28 # All k missing numbers are after the array
29 # Use the last element as anchor
30 last_idx = len(arr) - 1
31 missing_before_last = arr[last_idx] - last_idx - 1
32 return arr[last_idx] + (k - missing_before_last)
33 elif first_true_index == 0:
34 # The kth missing number is before arr[0]
35 return k
36 else:
37 # The kth missing number is between arr[first_true_index-1] and arr[first_true_index]
38 prev_idx = first_true_index - 1
39 missing_before_prev = arr[prev_idx] - prev_idx - 1
40 return arr[prev_idx] + (k - missing_before_prev)
411class Solution {
2 public int findKthPositive(int[] arr, int k) {
3 // Edge case: if arr[0] > k, all k missing numbers come before the array
4 if (arr[0] > k) {
5 return k;
6 }
7
8 // Binary search using the standard template
9 // Feasible function: arr[mid] - mid - 1 >= k
10 int left = 0;
11 int right = arr.length - 1;
12 int firstTrueIndex = -1;
13
14 while (left <= right) {
15 int mid = left + (right - left) / 2;
16
17 // Calculate how many positive integers are missing before arr[mid]
18 int missingCount = arr[mid] - mid - 1;
19
20 if (missingCount >= k) {
21 // Feasible: at least k missing numbers before this position
22 firstTrueIndex = mid;
23 right = mid - 1;
24 } else {
25 // Not feasible: need to search further right
26 left = mid + 1;
27 }
28 }
29
30 // Calculate the kth missing number
31 if (firstTrueIndex == -1) {
32 // All k missing numbers are after the array
33 int lastIdx = arr.length - 1;
34 int missingBeforeLast = arr[lastIdx] - lastIdx - 1;
35 return arr[lastIdx] + (k - missingBeforeLast);
36 } else if (firstTrueIndex == 0) {
37 // The kth missing number is before arr[0]
38 return k;
39 } else {
40 // The kth missing number is between arr[firstTrueIndex-1] and arr[firstTrueIndex]
41 int prevIdx = firstTrueIndex - 1;
42 int missingBeforePrev = arr[prevIdx] - prevIdx - 1;
43 return arr[prevIdx] + (k - missingBeforePrev);
44 }
45 }
46}
471class Solution {
2public:
3 int findKthPositive(vector<int>& arr, int k) {
4 // Edge case: if arr[0] > k, all k missing numbers come before the array
5 if (arr[0] > k) {
6 return k;
7 }
8
9 // Binary search using the standard template
10 // Feasible function: arr[mid] - mid - 1 >= k
11 int left = 0;
12 int right = arr.size() - 1;
13 int firstTrueIndex = -1;
14
15 while (left <= right) {
16 int mid = left + (right - left) / 2;
17
18 // Calculate how many positive integers are missing before arr[mid]
19 int missingCount = arr[mid] - mid - 1;
20
21 if (missingCount >= k) {
22 // Feasible: at least k missing numbers before this position
23 firstTrueIndex = mid;
24 right = mid - 1;
25 } else {
26 // Not feasible: need to search further right
27 left = mid + 1;
28 }
29 }
30
31 // Calculate the kth missing number
32 if (firstTrueIndex == -1) {
33 // All k missing numbers are after the array
34 int lastIdx = arr.size() - 1;
35 int missingBeforeLast = arr[lastIdx] - lastIdx - 1;
36 return arr[lastIdx] + (k - missingBeforeLast);
37 } else if (firstTrueIndex == 0) {
38 // The kth missing number is before arr[0]
39 return k;
40 } else {
41 // The kth missing number is between arr[firstTrueIndex-1] and arr[firstTrueIndex]
42 int prevIdx = firstTrueIndex - 1;
43 int missingBeforePrev = arr[prevIdx] - prevIdx - 1;
44 return arr[prevIdx] + (k - missingBeforePrev);
45 }
46 }
47};
481function findKthPositive(arr: number[], k: number): number {
2 // Edge case: if arr[0] > k, all k missing numbers come before the array
3 if (arr[0] > k) {
4 return k;
5 }
6
7 // Binary search using the standard template
8 // Feasible function: arr[mid] - mid - 1 >= k
9 let left = 0;
10 let right = arr.length - 1;
11 let firstTrueIndex = -1;
12
13 while (left <= right) {
14 const mid = Math.floor((left + right) / 2);
15
16 // Calculate how many positive integers are missing before arr[mid]
17 const missingCount = arr[mid] - mid - 1;
18
19 if (missingCount >= k) {
20 // Feasible: at least k missing numbers before this position
21 firstTrueIndex = mid;
22 right = mid - 1;
23 } else {
24 // Not feasible: need to search further right
25 left = mid + 1;
26 }
27 }
28
29 // Calculate the kth missing number
30 if (firstTrueIndex === -1) {
31 // All k missing numbers are after the array
32 const lastIdx = arr.length - 1;
33 const missingBeforeLast = arr[lastIdx] - lastIdx - 1;
34 return arr[lastIdx] + (k - missingBeforeLast);
35 } else if (firstTrueIndex === 0) {
36 // The kth missing number is before arr[0]
37 return k;
38 } else {
39 // The kth missing number is between arr[firstTrueIndex-1] and arr[firstTrueIndex]
40 const prevIdx = firstTrueIndex - 1;
41 const missingBeforePrev = arr[prevIdx] - prevIdx - 1;
42 return arr[prevIdx] + (k - missingBeforePrev);
43 }
44}
45Solution Approach
The implementation uses binary search with the standard template to find the first position where the count of missing numbers reaches k.
Feasible Function Definition
For any index i, the number of missing positive integers before arr[i] is arr[i] - i - 1. This is because if no numbers were missing, arr[i] would equal i + 1.
We define feasible(mid) = arr[mid] - mid - 1 >= k, which returns true when at least k numbers are missing before position mid. This creates the pattern:
[false, false, ..., false, true, true, ..., true]
We want to find the first index where this becomes true.
Binary Search Template
left, right = 0, len(arr) - 1
first_true_index = -1
while left <= right:
mid = (left + right) // 2
if arr[mid] - mid - 1 >= k: # feasible(mid)
first_true_index = mid
right = mid - 1
else:
left = mid + 1
Calculating the Final Answer
After the binary search:
- If
first_true_index == -1: No position haskmissing numbers, so the answer is after the array - If
first_true_index == 0andarr[0] > k: Allkmissing numbers are before the array starts, returnk - Otherwise: The answer lies between
arr[first_true_index - 1]andarr[first_true_index]
When first_true_index > 0, we use arr[first_true_index - 1] as the anchor point. The count of missing numbers before this position is arr[first_true_index - 1] - (first_true_index - 1) - 1. The k-th missing number is arr[first_true_index - 1] + (k - missing_count).
Time Complexity: O(log n) where n is the length of the array.
Space Complexity: O(1) as we only use a constant amount of extra space.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with arr = [2, 3, 4, 7, 11] and k = 5.
Step 1: Check edge case
- Is
arr[0] > k? Is2 > 5? No, so we continue with binary search.
Step 2: Understand the feasible function Before binary search, let's see the missing count at each index:
- Index 0:
arr[0] = 2, missing =2 - 0 - 1 = 1, feasible(0) =1 >= 5? false - Index 1:
arr[1] = 3, missing =3 - 1 - 1 = 1, feasible(1) =1 >= 5? false - Index 2:
arr[2] = 4, missing =4 - 2 - 1 = 1, feasible(2) =1 >= 5? false - Index 3:
arr[3] = 7, missing =7 - 3 - 1 = 3, feasible(3) =3 >= 5? false - Index 4:
arr[4] = 11, missing =11 - 4 - 1 = 6, feasible(4) =6 >= 5? true
Pattern: [false, false, false, false, true] → first_true_index should be 4.
Step 3: Binary search using template
Initialize: left = 0, right = 4, first_true_index = -1
Iteration 1: left=0, right=4
mid = (0 + 4) // 2 = 2- Missing at index 2:
4 - 2 - 1 = 1 - Is
1 >= 5? No (not feasible) left = mid + 1 = 3
Iteration 2: left=3, right=4
mid = (3 + 4) // 2 = 3- Missing at index 3:
7 - 3 - 1 = 3 - Is
3 >= 5? No (not feasible) left = mid + 1 = 4
Iteration 3: left=4, right=4
mid = (4 + 4) // 2 = 4- Missing at index 4:
11 - 4 - 1 = 6 - Is
6 >= 5? Yes (feasible!) first_true_index = 4,right = mid - 1 = 3
Loop ends as left > right (4 > 3).
Step 4: Calculate the answer
first_true_index = 4, so we look atarr[first_true_index - 1] = arr[3] = 7- Missing numbers before
arr[3]:7 - 3 - 1 = 3 - We need the 5th missing number:
k - missing_count = 5 - 3 = 2more afterarr[3] - Answer:
arr[3] + 2 = 7 + 2 = 9
Let's verify: The missing positive integers are [1, 5, 6, 8, 9, ...]. The 5th one is indeed 9. ✓
Time and Space Complexity
Time Complexity: O(log n) where n is the length of the input array arr.
The algorithm uses binary search on the array. The binary search performs at most log n iterations since it halves the search space in each iteration. Each iteration performs constant time operations:
- Calculating
mid = (left + right) >> 1isO(1) - Accessing
arr[mid]and performing arithmetic operationsarr[mid] - mid - 1isO(1) - Comparing and updating
leftorrightisO(1)
The initial check if arr[0] > k and the final calculation are both O(1) operations.
Space Complexity: O(1)
The algorithm uses only a constant amount of extra space:
- Variables
left,right, andmidfor the binary search - No additional data structures are created
- No recursive calls that would use the call stack
The space used does not depend on the size of the input array.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Using Wrong Binary Search Template Variant
A common mistake is using while left < right with right = mid instead of the standard template with first_true_index tracking.
Wrong variant:
while left < right: mid = (left + right) // 2 if arr[mid] - mid - 1 >= k: right = mid else: left = mid + 1 return arr[left - 1] + ... # Prone to index errors!
Correct template:
first_true_index = -1 while left <= right: mid = (left + right) // 2 if arr[mid] - mid - 1 >= k: first_true_index = mid right = mid - 1 else: left = mid + 1 # Handle first_true_index == -1 case explicitly
2. Index Out of Bounds When first_true_index is -1
After binary search, if no position satisfies the feasible condition, first_true_index remains -1. Accessing arr[first_true_index - 1] without checking causes errors.
Solution:
Always check if first_true_index == -1 before using it:
if first_true_index == -1:
# Handle case where k-th missing is after the array
last_idx = len(arr) - 1
return arr[last_idx] + (k - (arr[last_idx] - last_idx - 1))
3. Off-by-One Error in Missing Count Formula
Forgetting the -1 in the formula arr[i] - i - 1 is a frequent mistake.
Wrong formula: arr[i] - i
Correct formula: arr[i] - i - 1
Example:
If arr = [2] at index 0, missing count should be 1 (the number 1 is missing).
- Wrong:
2 - 0 = 2(incorrect) - Correct:
2 - 0 - 1 = 1(correct)
4. Not Handling Edge Case When first_true_index is 0
When first_true_index == 0, the k-th missing number is before arr[0]. Trying to access arr[first_true_index - 1] causes an index error.
Solution:
if first_true_index == 0: return k # All k missing numbers are before arr[0]
5. Integer Overflow in Mid Calculation
In some languages, (left + right) / 2 can overflow for large values.
Solution:
int mid = left + (right - left) / 2;
Template-Compliant Solution:
class Solution:
def findKthPositive(self, arr: List[int], k: int) -> int:
if arr[0] > k:
return k
left, right = 0, len(arr) - 1
first_true_index = -1
while left <= right:
mid = (left + right) // 2
if arr[mid] - mid - 1 >= k:
first_true_index = mid
right = mid - 1
else:
left = mid + 1
if first_true_index == -1:
last_idx = len(arr) - 1
return arr[last_idx] + (k - (arr[last_idx] - last_idx - 1))
elif first_true_index == 0:
return k
else:
prev_idx = first_true_index - 1
return arr[prev_idx] + (k - (arr[prev_idx] - prev_idx - 1))
Which data structure is used to implement priority queue?
Recommended Readings
https assets algo monster cover_photos Binary_Search svg Binary Search Intuition Binary search is an efficient array search algorithm It works by narrowing down the search range by half each time If you have looked up a word in a physical dictionary you've already used binary search in real life Let's
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 If you prefer videos here's a video that explains recursion in a fun and easy way 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 him
Want a Structured Path to Master System Design Too? Don’t Miss This!