Facebook Pixel

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] and k = 5, the missing positive integers are [1, 5, 6, 8, 9, ...]. The 5th missing positive integer is 9.
  • If arr = [1, 2, 3, 4] and k = 2, the missing positive integers are [5, 6, 7, 8, ...]. The 2nd missing positive integer is 6.

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:

  1. First checks if the answer is before the first element (when arr[0] > k)
  2. Uses binary search to find the position where exactly k missing numbers have occurred
  3. Calculates the final answer based on the last element before the position found and adjusts for the remaining missing numbers needed
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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 than k missing numbers
  • The kth missing number lies somewhere after arr[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 Approach

The implementation uses binary search to efficiently find the position in the array where we have accumulated enough missing numbers.

Step 1: Handle the edge case

if arr[0] > k:
    return k

If the first element is greater than k, it means all k missing numbers occur before the array starts. For example, if arr = [5, 6, 7] and k = 3, the missing numbers are [1, 2, 3, 4, ...], so we simply return k.

Step 2: Binary search setup

left, right = 0, len(arr)

We initialize our search boundaries. Note that right is set to len(arr) (not len(arr) - 1) to handle cases where the answer might be after the last element.

Step 3: Binary search to find the critical position

while left < right:
    mid = (left + right) >> 1
    if arr[mid] - mid - 1 >= k:
        right = mid
    else:
        left = mid + 1
  • Calculate mid using bit shift (>> 1 is equivalent to dividing by 2)
  • Check how many missing numbers exist before arr[mid] using the formula arr[mid] - mid - 1
  • If the count of missing numbers at mid is at least k, the answer is at or before mid, so we move right = mid
  • Otherwise, we need to search further right, so left = mid + 1

After the binary search, left points to the first position where the count of missing numbers is at least k.

Step 4: Calculate the final answer

return arr[left - 1] + k - (arr[left - 1] - (left - 1) - 1)

At this point:

  • arr[left - 1] is the largest element that has fewer than k missing numbers before it
  • arr[left - 1] - (left - 1) - 1 gives us the count of missing numbers before arr[left - 1]
  • We need to find the kth missing number, which is k - (count of missing before arr[left - 1]) positions after arr[left - 1]

The formula simplifies to adding the remaining missing count to arr[left - 1] to get our answer.

Time Complexity: O(log n) where n is the length of the array, due to binary search. 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 Evaluator

Example 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? Is 2 > 5? No, so we continue.

Step 2: Calculate missing numbers at each position Before we start binary search, let's understand what's happening at each index:

  • Index 0: arr[0] = 2, missing count = 2 - 0 - 1 = 1 (missing: [1])
  • Index 1: arr[1] = 3, missing count = 3 - 1 - 1 = 1 (missing: [1])
  • Index 2: arr[2] = 4, missing count = 4 - 2 - 1 = 1 (missing: [1])
  • Index 3: arr[3] = 7, missing count = 7 - 3 - 1 = 3 (missing: [1, 5, 6])
  • Index 4: arr[4] = 11, missing count = 11 - 4 - 1 = 6 (missing: [1, 5, 6, 8, 9, 10])

Step 3: Binary search Initialize: left = 0, right = 5

Iteration 1:

  • mid = (0 + 5) >> 1 = 2
  • Missing at index 2: arr[2] - 2 - 1 = 4 - 2 - 1 = 1
  • Is 1 >= 5? No, so left = mid + 1 = 3

Iteration 2:

  • mid = (3 + 5) >> 1 = 4
  • Missing at index 4: arr[4] - 4 - 1 = 11 - 4 - 1 = 6
  • Is 6 >= 5? Yes, so right = mid = 4

Iteration 3:

  • mid = (3 + 4) >> 1 = 3
  • Missing at index 3: arr[3] - 3 - 1 = 7 - 3 - 1 = 3
  • Is 3 >= 5? No, so left = mid + 1 = 4

Loop ends as left = right = 4.

Step 4: Calculate the answer

  • left - 1 = 3, so we look at arr[3] = 7
  • Missing numbers before arr[3]: 7 - 3 - 1 = 3
  • We need the 5th missing number, so we need 5 - 3 = 2 more missing numbers after arr[3]
  • Answer: arr[3] + (k - missing_before) = 7 + (5 - 3) = 7 + 2 = 9

Let's verify: The missing positive integers are [1, 5, 6, 8, 9, ...]. The 5th one is indeed 9. ✓

Solution Implementation

1class Solution:
2    def findKthPositive(self, arr: List[int], k: int) -> int:
3        # If the first element is greater than k, then the kth missing number is k itself
4        # Example: arr = [5, 6, 7], k = 3 -> missing are 1, 2, 3, 4... so 3rd missing is 3
5        if arr[0] > k:
6            return k
7      
8        # Binary search to find the position where we have at least k missing numbers
9        left, right = 0, len(arr)
10      
11        while left < right:
12            mid = (left + right) // 2
13          
14            # Calculate how many positive integers are missing before arr[mid]
15            # arr[mid] - mid - 1 gives the count of missing numbers before index mid
16            # Example: arr[2] = 7, then 7 - 2 - 1 = 4 missing numbers (1,2,3,4 are missing)
17            missing_count = arr[mid] - mid - 1
18          
19            if missing_count >= k:
20                # We have at least k missing numbers before mid, search in left half
21                right = mid
22            else:
23                # We don't have enough missing numbers yet, search in right half
24                left = mid + 1
25      
26        # After binary search, left points to the smallest index where we have >= k missing numbers
27        # We need to find the kth missing number based on arr[left - 1]
28        # Formula: arr[left - 1] + (k - count of missing numbers before arr[left - 1])
29        prev_index = left - 1
30        missing_before_prev = arr[prev_index] - prev_index - 1
31        return arr[prev_index] + k - missing_before_prev
32
1class Solution {
2    public int findKthPositive(int[] arr, int k) {
3        // If the first element is greater than k, then the k-th missing number is k itself
4        // Example: arr = [5,6,7], k = 3 -> missing numbers before 5 are [1,2,3,4], so answer is 3
5        if (arr[0] > k) {
6            return k;
7        }
8      
9        // Binary search to find the position where we have at least k missing numbers
10        int left = 0;
11        int right = arr.length;
12      
13        while (left < right) {
14            int mid = left + (right - left) / 2;
15          
16            // Calculate number of missing positive integers before arr[mid]
17            // Formula: arr[mid] - (mid + 1) gives count of missing numbers before index mid
18            // Example: arr[2] = 7, missing count = 7 - (2 + 1) = 4 missing numbers [1,2,3,5]
19            int missingCount = arr[mid] - mid - 1;
20          
21            if (missingCount >= k) {
22                // We have at least k missing numbers before arr[mid], search left half
23                right = mid;
24            } else {
25                // We need more missing numbers, search right half
26                left = mid + 1;
27            }
28        }
29      
30        // After binary search, left points to the first position where missing count >= k
31        // We need to find the k-th missing number based on arr[left - 1]
32        // Formula breakdown:
33        // - arr[left - 1]: the last element before we have k missing numbers
34        // - (arr[left - 1] - left): count of missing numbers before arr[left - 1]
35        // - k - (arr[left - 1] - left): how many more missing numbers we need after arr[left - 1]
36        // - Final answer: arr[left - 1] + remaining missing numbers needed
37        return arr[left - 1] + k - (arr[left - 1] - left);
38    }
39}
40
1class Solution {
2public:
3    int findKthPositive(vector<int>& arr, int k) {
4        // If the first element is greater than k, then the k-th missing number is k itself
5        // Example: arr = [5,6,7], k = 3 → missing numbers are 1,2,3,4... so 3rd missing is 3
6        if (arr[0] > k) {
7            return k;
8        }
9      
10        // Binary search to find the position where k-th missing number should be
11        int left = 0;
12        int right = arr.size();
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            // Formula: arr[mid] - (mid + 1) gives count of missing numbers before index mid
19            // Example: arr[2] = 7, then 7 - (2 + 1) = 4 missing numbers (1,2,3,4)
20            int missingCount = arr[mid] - mid - 1;
21          
22            if (missingCount >= k) {
23                // k-th missing number is before or at mid position
24                right = mid;
25            } else {
26                // k-th missing number is after mid position
27                left = mid + 1;
28            }
29        }
30      
31        // After binary search, left points to the smallest index where 
32        // the count of missing numbers >= k
33        // Calculate the k-th missing positive integer
34        // Start from arr[left-1] and add the remaining missing numbers needed
35        int previousIndex = left - 1;
36        int missingBeforePrevious = arr[previousIndex] - previousIndex - 1;
37        int remainingMissing = k - missingBeforePrevious;
38      
39        return arr[previousIndex] + remainingMissing;
40    }
41};
42
1function findKthPositive(arr: number[], k: number): number {
2    // If the first element is greater than k, then the k-th missing number is k itself
3    // Example: arr = [5,6,7], k = 3 → missing numbers are 1,2,3,4... so 3rd missing is 3
4    if (arr[0] > k) {
5        return k;
6    }
7  
8    // Binary search to find the position where k-th missing number should be
9    let left = 0;
10    let right = arr.length;
11  
12    while (left < right) {
13        const mid = left + Math.floor((right - left) / 2);
14      
15        // Calculate how many positive integers are missing before arr[mid]
16        // Formula: arr[mid] - (mid + 1) gives count of missing numbers before index mid
17        // Example: arr[2] = 7, then 7 - (2 + 1) = 4 missing numbers (1,2,3,4)
18        const missingCount = arr[mid] - mid - 1;
19      
20        if (missingCount >= k) {
21            // k-th missing number is before or at mid position
22            right = mid;
23        } else {
24            // k-th missing number is after mid position
25            left = mid + 1;
26        }
27    }
28  
29    // After binary search, left points to the smallest index where 
30    // the count of missing numbers >= k
31    // Calculate the k-th missing positive integer
32    // Start from arr[left-1] and add the remaining missing numbers needed
33    const previousIndex = left - 1;
34    const missingBeforePrevious = arr[previousIndex] - previousIndex - 1;
35    const remainingMissing = k - missingBeforePrevious;
36  
37    return arr[previousIndex] + remainingMissing;
38}
39

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) >> 1 is O(1)
  • Accessing arr[mid] and performing arithmetic operations arr[mid] - mid - 1 is O(1)
  • Comparing and updating left or right is O(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, and mid for 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. Index Out of Bounds Error

The most common pitfall occurs when calculating the final answer. After the binary search, if left becomes 0 (when all k missing numbers should come before the first element), accessing arr[left - 1] will cause an index out of bounds error.

Problematic scenario:

arr = [5, 6, 7], k = 2
# After binary search, left = 0
# arr[left - 1] = arr[-1] → IndexError!

Solution: Add a check after the binary search to handle this edge case:

if left == 0:
    return k

2. Integer Overflow in Binary Search

When calculating mid = (left + right) // 2, if the array is extremely large, left + right could potentially overflow in some languages (though Python handles big integers well).

Solution: Use the alternative formula to avoid overflow:

mid = left + (right - left) // 2

3. Incorrect Binary Search Boundaries

Setting right = len(arr) - 1 instead of right = len(arr) will cause incorrect results when the answer lies after the last element of the array.

Problematic scenario:

arr = [1, 2, 3], k = 5
# With right = len(arr) - 1, the search space doesn't include the possibility
# that all k missing numbers are after the array

Solution: Always initialize right = len(arr) to ensure the search space includes positions beyond the array.

4. Off-by-One Error in Missing Count Formula

Forgetting the -1 in the formula arr[i] - i - 1 is a frequent mistake. The formula represents: (value at index i) - (expected value if no gaps) = missing count.

Wrong formula: arr[i] - i Correct formula: arr[i] - i - 1

Example to remember: 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)

5. Not Handling Empty Array Edge Case

Though not typically expected in this problem, an empty array would cause immediate failure.

Solution: Add a check at the beginning:

if not arr:
    return k

Complete Corrected Solution:

class Solution:
    def findKthPositive(self, arr: List[int], k: int) -> int:
        if not arr:
            return k
          
        if arr[0] > k:
            return k
      
        left, right = 0, len(arr)
      
        while left < right:
            mid = left + (right - left) // 2
            missing_count = arr[mid] - mid - 1
          
            if missing_count >= k:
                right = mid
            else:
                left = mid + 1
      
        # Handle the case when left == 0
        if left == 0:
            return k
          
        prev_index = left - 1
        missing_before_prev = arr[prev_index] - prev_index - 1
        return arr[prev_index] + k - missing_before_prev
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

What's the output of running the following function using input 56?

1KEYBOARD = {
2    '2': 'abc',
3    '3': 'def',
4    '4': 'ghi',
5    '5': 'jkl',
6    '6': 'mno',
7    '7': 'pqrs',
8    '8': 'tuv',
9    '9': 'wxyz',
10}
11
12def letter_combinations_of_phone_number(digits):
13    def dfs(path, res):
14        if len(path) == len(digits):
15            res.append(''.join(path))
16            return
17
18        next_number = digits[len(path)]
19        for letter in KEYBOARD[next_number]:
20            path.append(letter)
21            dfs(path, res)
22            path.pop()
23
24    res = []
25    dfs([], res)
26    return res
27
1private static final Map<Character, char[]> KEYBOARD = Map.of(
2    '2', "abc".toCharArray(),
3    '3', "def".toCharArray(),
4    '4', "ghi".toCharArray(),
5    '5', "jkl".toCharArray(),
6    '6', "mno".toCharArray(),
7    '7', "pqrs".toCharArray(),
8    '8', "tuv".toCharArray(),
9    '9', "wxyz".toCharArray()
10);
11
12public static List<String> letterCombinationsOfPhoneNumber(String digits) {
13    List<String> res = new ArrayList<>();
14    dfs(new StringBuilder(), res, digits.toCharArray());
15    return res;
16}
17
18private static void dfs(StringBuilder path, List<String> res, char[] digits) {
19    if (path.length() == digits.length) {
20        res.add(path.toString());
21        return;
22    }
23    char next_digit = digits[path.length()];
24    for (char letter : KEYBOARD.get(next_digit)) {
25        path.append(letter);
26        dfs(path, res, digits);
27        path.deleteCharAt(path.length() - 1);
28    }
29}
30
1const KEYBOARD = {
2    '2': 'abc',
3    '3': 'def',
4    '4': 'ghi',
5    '5': 'jkl',
6    '6': 'mno',
7    '7': 'pqrs',
8    '8': 'tuv',
9    '9': 'wxyz',
10}
11
12function letter_combinations_of_phone_number(digits) {
13    let res = [];
14    dfs(digits, [], res);
15    return res;
16}
17
18function dfs(digits, path, res) {
19    if (path.length === digits.length) {
20        res.push(path.join(''));
21        return;
22    }
23    let next_number = digits.charAt(path.length);
24    for (let letter of KEYBOARD[next_number]) {
25        path.push(letter);
26        dfs(digits, path, res);
27        path.pop();
28    }
29}
30

Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More