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 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)
41
1class 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}
47
1class 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};
48
1function 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}
45

Solution 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 has k missing numbers, so the answer is after the array
  • If first_true_index == 0 and arr[0] > k: All k missing numbers are before the array starts, return k
  • Otherwise: The answer lies between arr[first_true_index - 1] and arr[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 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 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 at arr[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 = 2 more after arr[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) >> 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. 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))
Loading...
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which data structure is used to implement priority queue?


Recommended Readings

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

Load More