786. K-th Smallest Prime Fraction

1. Description

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 kth smallest fraction considered. Return your answer as an array of integers of size 2, where answer[0] == arr[i] and answer[1] == arr[j].

2. Example

Example 1:
Input: arr = [1,2,3,5], k = 3
Output: [2,5]
Explanation: The fractions to be considered in sorted order are:
1/5, 1/3, 2/5, 1/2, 3/5, and 2/3.
The third fraction is 2/5.

Example 2:
Input: arr = [1,7], k = 1
Output: [1,7]

3. Constraints

  • 2 <= arr.length <= 1000
  • 1 <= arr[i] <= $3 * 10^4$
  • arr[0] == 1
  • arr[i] is a prime number for i > 0
  • All the numbers of arr are unique and sorted in strictly increasing order
  • 1 <= k <= arr.length * (arr.length - 1) / 2

4. Solutions

Heap(Priority Queue)

n = arr.size()
Time complexity: O(klogn)
Space complexity: O(n)

class Solution {
public:
    vector<int> kthSmallestPrimeFraction(const vector<int> &arr, int k) {
        auto greater = [&](const pair<int, int> &x, const pair<int, int> &y) {
            return arr[x.first] * arr[y.second] > arr[y.first] * arr[x.second];
        };
        priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(greater)> fraction_queue(
            greater);
        // since all the numbers of arr are unique and sorted in strictly increasing order
        // for the fraction i/j, arr[i]/arr[j] always < arr[i+1]/arr[j]
        // we maintain a queue to include every denominator j, and find min value every time
        // until to find kth value
        for (int i = 1; i < arr.size(); ++i) {
            fraction_queue.emplace(0, i);
        }

        for (int i = 1; i < k; ++i) {
            auto [numerator, denominator] = fraction_queue.top();
            fraction_queue.pop();

            if (numerator + 1 < denominator) {
                fraction_queue.emplace(numerator + 1, denominator);
            }
        }

        return {arr[fraction_queue.top().first], arr[fraction_queue.top().second]};
    }
};

n = arr.size(), C is upper bound of search times
Time complexity: O(nlogC)
Space complexity: O(1)

class Solution {
public:
    vector<int> kthSmallestPrimeFraction(const vector<int> &arr, int k) {
        // 1 <= arr[i] <= 3 * 10^4
        // so min value is 1 / 3 * 10^4
        // and min diff is (1 / 3 * 10^4 - 1) - (1 / 3 * 10^4)
        // it is about 1 / 9 * 10^8, which needs 30 times binary search(30 times / 2)
        for (double left = 0.0, right = 1.0; left < right;) {
            double mid = (left + right) / 2;

            int x = 0, y = 1, count = 0; // x/y is used to record the max number
            for (int i = 0, j = 1; j < arr.size(); ++j) {
                while ((double)arr[i] / arr[j] < mid) {
                    if (arr[i] * y > arr[j] * x) { // find the max number
                        x = arr[i];
                        y = arr[j];
                    }
                    ++i;
                }
                count += i;
                // i is an index, but it is the first invalid index
                // when we need an count, we use (i + 1), so the count is (i - 1 + 1), i.e., i
            }

            if (count == k) {
                return {x, y};
            }

            count < k ? left = mid : right = mid;
        }

        return {};
    }
};
comments powered by Disqus