Select the k-th smallest fraction formed by pairs from a sorted array using heap or binary search.
Kth Smallest Fraction selects the k-th smallest value among fractions of the form:
where the array is sorted and:
This problem appears in number theory and ranking problems. Direct enumeration gives fractions, which is too large.
Problem
Given a sorted array of positive integers and an integer , return the k-th smallest fraction among all pairs with .
Algorithm 1: Min Heap
Treat each denominator as a column. Start with the smallest numerator for each denominator.
kth_smallest_fraction(A, k):
H = empty min heap
for j from 1 to n - 1:
push (A[0] / A[j], i=0, j) into H
repeat k - 1 times:
(value, i, j) = pop minimum from H
if i + 1 < j:
push (A[i + 1] / A[j], i + 1, j) into H
return top of HAlgorithm 2: Binary Search on Value
Search for a value such that exactly fractions are less than or equal to .
kth_smallest_fraction(A, k):
low = 0.0
high = 1.0
while true:
mid = (low + high) / 2
count, best_num, best_den = count_less_equal(A, mid)
if count == k:
return (best_num, best_den)
else if count < k:
low = mid
else:
high = midCounting uses two pointers:
count_less_equal(A, x):
count = 0
best_num = 0
best_den = 1
j = 1
for i from 0 to n - 2:
while j < n and A[i] > x * A[j]:
j = j + 1
if j == n:
break
count = count + (n - j)
if A[i] * best_den > best_num * A[j]:
best_num = A[i]
best_den = A[j]
return count, best_num, best_denExample
Let:
All fractions:
Sorted:
For , the answer is:
Correctness
In the heap method, each denominator generates a sorted sequence of fractions. The heap merges these sequences, always extracting the next smallest fraction.
In the binary search method, the predicate “number of fractions is at least ” is monotone. The counting step correctly counts valid pairs using the sorted structure.
Tracking the best fraction during counting ensures that the exact k-th fraction is returned.
Complexity
| method | time | space |
|---|---|---|
| heap | ||
| binary search |
Here is the precision range for floating point search.
When to Use
Use the heap method when is small. Use binary search when is large and may be large.
The binary search method avoids storing many candidates and gives strong performance for large inputs.
Implementation
import heapq
def kth_smallest_fraction(a, k):
n = len(a)
heap = []
for j in range(1, n):
heapq.heappush(heap, (a[0] / a[j], 0, j))
for _ in range(k - 1):
_, i, j = heapq.heappop(heap)
if i + 1 < j:
heapq.heappush(heap, (a[i + 1] / a[j], i + 1, j))
_, i, j = heapq.heappop(heap)
return a[i], a[j]func KthSmallestFraction(a []int, k int) (int, int) {
type Node struct {
value float64
i, j int
}
h := &MinHeapFraction{}
heap.Init(h)
n := len(a)
for j := 1; j < n; j++ {
heap.Push(h, Node{float64(a[0]) / float64(a[j]), 0, j})
}
for t := 0; t < k-1; t++ {
node := heap.Pop(h).(Node)
i, j := node.i, node.j
if i+1 < j {
heap.Push(h, Node{float64(a[i+1]) / float64(a[j]), i + 1, j})
}
}
node := heap.Pop(h).(Node)
return a[node.i], a[node.j]
}