题目
思路一 自定义排序
用vector把分数的分子分母以pair的形式存进来,再自定义排序函数,把小的放前,大的放后,分数的分子分母交叉相乘后比较。
代码一
class Solution {
public:
vector<int> kthSmallestPrimeFraction(vector<int>& arr, int k) {
int n=arr.size();
vector<pair<int,int>> frac;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
frac.push_back({arr[i],arr[j]});
}
}
sort(frac.begin(),frac.end(),[&](const auto& x,const auto& y){
return x.first*y.second<x.second*y.first;
});
return {frac[k-1].first,frac[k-1].second};
}
};
思路二 优先队列
初始时,在优先队列中存入n-1个分数,每个分数的分子是数组中第一个数,分母是第二个到最后一个数。每次从优先队列中取出一个最小的数据,记为arr[i]/arr[j],再放入arr[i+1]/arr[j]。这样第k次取出的数就是第k小的数。
代码二
class Solution {
public:
// struct cmp{
// bool operator()(pair<int,int> a,pair<int,int> b){
// return a.first*b.second>b.first*a.second;
// }
// };
vector<int> kthSmallestPrimeFraction(vector<int>& arr, int k) {
int n=arr.size();
auto cmp = [&](const pair<int, int>& x, const pair<int, int>& y) {
return arr[x.first] * arr[y.second] > arr[x.second] * arr[y.first];
};
priority_queue<pair<int,int>,vector<pair<int,int>>,decltype(cmp)> pq(cmp);
for(int j=0;j<n;j++)
pq.emplace(0,j);
for(int cnt=1;cnt<k;cnt++){
auto [i,j]=pq.top();
pq.pop();
pq.emplace(i+1,j);
}
return {arr[pq.top().first],arr[pq.top().second]};
}
};
思路三 二分查找+双指针
double型二分查找,构建check函数,用双指针指向分子和分母,直到找到最接近的。
代码三
class Solution {
public:
double eps=1e-8;
vector<int> arr;
int n,a,b;
vector<int> kthSmallestPrimeFraction(vector<int>& _arr, int k) {
arr=_arr;
n=arr.size();
double l=0,r=1;
while(r-l>eps){
double mid=(l+r)/2;
if(check(mid)>=k) r=mid;
else l=mid;
}
return {a,b};
}
int check(double x){
int ans=0;
for(int i=0,j=1;j<n;j++){
while(arr[i+1]*1.0/arr[j]<=x)i++;
if(arr[i]*1.0/arr[j]<=x)ans+=i+1;
if(abs(arr[i]*1.0/arr[j]-x)<eps){
a=arr[i];
b=arr[j];
}
}
return ans;
}
};