找出第k小的数对距离
数对 (a,b) 由整数 a 和 b 组成,其数对距离定义为 a 和 b 的绝对差值。
给你一个整数数组 nums 和一个整数 k ,数对由 nums[i] 和 nums[j] 组成且满足 0 <= i < j < nums.length ,返回 所有数对距离中第 k 小的数对距离。
1. 小根堆二维搜索(超时)
class Solution {
public:
int smallestDistancePair(vector<int>& nums, int k) {
int n = nums.size();
sort(nums.begin(),nums.end());
priority_queue<tuple<int, int, int>> pq;
pq.emplace(0, 0, 0); // 取相反数变成小顶堆
while (!pq.empty() ){
auto [_, i, j] = pq.top(); pq.pop();//两个数组对应下标
if(i!=j) k--;
if(k==0) return nums[j]-nums[i];
if(i==j&&i+1<n)
pq.emplace(0, i+1, j+1);
if (j + 1 < n )//无条件移动
pq.emplace(-(nums[j+1]-nums[i]), i, j+1);
}
return 0;
}
};
2. 二分法
class Solution {
public:
int smallestDistancePair(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());//排序
int n = nums.size();
int left = 0, right = nums.back() - nums.front();//最小数对距离和最大数对距离
while (left < right) {
int mid = (left + right) / 2;
int cnt = 0;
//统计以j为右边界,距离小于等于mid 的数对个数
for (int j = 0; j < n; j++) {
int leftval = nums[j] - mid;//这个是区间最左侧的值
auto leftbound = lower_bound(nums.begin(), nums.begin() + j, leftval);//获得左边界
int i = leftbound - nums.begin();
cnt += j - i; //右边界-左边界,获得左边界可以取得的个数,即满足条件的数对数
}
//
if (cnt < k) left = mid + 1;//不满足
else right = mid;
}
return right;
}
};