K-th Smallest Prime Fraction - Complete Solution Guide
K-th Smallest Prime Fraction is LeetCode problem 786, a Medium level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.
Problem Statement
You are given a sorted integer array arr containing 1 and prime numbers, where all the integers of arr are unique. You are also given an integer k . For every i and j where 0 <= i < j < arr.length , we consider the fraction arr[i] / arr[j] . Return the k th smallest fraction considered . Return your answer as an array of integers of size 2 , where answer[0] == arr[i] and answer[1] == arr[j] . Example 1: Input: arr = [1,2,3,5], k = 3 Output: [2,5] Explanation: The fractions to be considered in so
Detailed Explanation
The problem asks us to find the k-th smallest fraction formed by pairs of elements in a sorted array `arr` containing 1 and prime numbers. Each fraction is of the form `arr[i] / arr[j]` where `0 <= i < j < arr.length`. The task is to return the pair `[arr[i], arr[j]]` that represents the k-th smallest fraction when all possible fractions are sorted in ascending order. The input is a sorted array of integers `arr` and an integer `k`. The output is an array of two integers representing the numerator and denominator of the k-th smallest fraction.
Solution Approach
The solution employs a binary search algorithm to find the k-th smallest fraction. The binary search operates on the possible range of fraction values, which is between 0 and 1. In each iteration, the algorithm calculates a 'mid' value and counts the number of fractions in the array that are less than this 'mid' value. The count is determined using a two-pointer approach. If the count is less than k, the lower bound of the search space is adjusted to 'mid'; otherwise, the upper bound is adjusted to 'mid'. This process continues until the difference between the upper and lower bounds is sufficiently small (less than 1e-9). The numerator and denominator of the fraction closest to the final 'mid' value are then returned.
Step-by-Step Algorithm
- Step 1: Initialize `low` to 0.0 and `high` to 1.0, representing the lower and upper bounds of possible fraction values.
- Step 2: Initialize `result_p` and `result_q` to 0 and 1, respectively. These will store the numerator and denominator of the closest fraction found so far.
- Step 3: Perform a binary search while `high - low > 1e-9`.
- Step 4: Calculate `mid = low + (high - low) / 2`.
- Step 5: Initialize `count` to 0, `p` to 0, and `q` to 1. `count` will store the number of fractions smaller than `mid`, and `p/q` will store the largest fraction smaller than `mid` found so far.
- Step 6: Use a two-pointer approach to count the fractions smaller than `mid`. Iterate through the array using `i` from 0 to `n - 2`. For each `i`, find the largest `j` such that `arr[i] / arr[j] < mid` or `arr[i] < mid * arr[j]`. The number of fractions `arr[i] / arr[j]` smaller than `mid` is then `n - j`.
- Step 7: Inside the inner loop, if `arr[i] / arr[j]` is greater than the current `p/q`, update `p` and `q` to `arr[i]` and `arr[j]`, respectively.
- Step 8: If `count < k`, update `low = mid`. This means that the 'mid' value is too small, and we need to search in the upper half of the range.
- Step 9: Otherwise, update `result_p = p`, `result_q = q`, and `high = mid`. This means that the 'mid' value is too large, and we need to search in the lower half of the range. Also update the best known fraction.
- Step 10: After the binary search completes, return `[result_p, result_q]`.
Key Insights
- Insight 1: Binary search is an effective approach since we're looking for the k-th smallest value within a range of possible fractions (0 to 1). Instead of generating all fractions and sorting them, which would be O(n^2 log n), we can use binary search to find the k-th smallest fraction by repeatedly guessing a value and counting how many fractions are smaller than our guess.
- Insight 2: A crucial optimization is to avoid explicitly calculating all fractions. Instead, for a given 'mid' value in our binary search, we can efficiently count the number of fractions `arr[i] / arr[j]` that are less than 'mid' in O(n) time using a two-pointer approach.
- Insight 3: The problem constraints guarantee the existence of the k-th smallest fraction, and the sorted nature of the input array is crucial for the efficiency of the two-pointer technique within the binary search.
Complexity Analysis
Time Complexity: O(n log(1/epsilon))
Space Complexity: O(1)
Topics
This problem involves: Array, Two Pointers, Binary Search, Sorting, Heap (Priority Queue).
Companies
Asked at: Pony.ai.