版权声明:本文为博主原创文章,博客地址:https://blog.csdn.net/qq_41855420,未经博主允许不得转载。 https://blog.csdn.net/qq_41855420/article/details/89603875
给定一个整数数组,返回所有数对之间的第 k 个最小距离。一对 (A, B) 的距离被定义为 A 和 B 之间的绝对差值。
示例 1:
输入:
nums = [1,3,1]
k = 1
输出:0
解释:
所有数对如下:
(1,3) -> 2
(1,1) -> 0
(3,1) -> 2
因此第 1 个最小距离的数对是 (1,1),它们之间的距离为 0。
提示:
2 <= len(nums) <= 10000.
0 <= nums[i] < 1000000.
1 <= k <= len(nums) * (len(nums) - 1) / 2.
思路分析: 与 LeetCode 乘法表中第k小的数(二分搜索) 非常类似。
最大的距离必定是最大值 - 最小值,而最小的距离可能是0(也可能比0大)。所以我们采用二分法,初始化left = 0, right = 最大距离。对于mid = (left + right) / 2,我们计算距离小于等于k个距离对的个数shortDisMid。
如果shortDisMid < k, 则第k小的距离对必定不会出现在[left, mid],所以修改left = mid + 1
否则 right = mid
class Solution {
public:
int smallestDistancePair(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());//按照升序排序
//二分搜索的三个指针,left初始化为0,right初始化为最大的距离
int left = 0, right = nums.back() - nums[0], mid;
while (left < right) {
mid = (left + right) / 2;
int shortDisMid = findDistaceShort(nums, mid);//获取距离大小不超过k的距离对的个数
//缩小[left, right]区间
if (shortDisMid < k) {
//<= mid的距离对个数小于k,则第k小的距离必定不会出现在[left, mid]
left = mid + 1;
}
else {
right = mid;
}
}
return left;
}
//寻找距离不超过distance的个数(nums已经按照升序排序)
int findDistaceShort(vector<int>& nums, int distance) {
//rightIndex代表的是在index左边且与nums[index]的距离不超过distanc的下标
int numsSize = nums.size(), res = 0, rightIndex = numsSize - 1;
for (int index = numsSize - 2; index >= 0; --index) {
//修正index左边与与nums[index]的距离不超过distanc的下标
while (rightIndex > index && nums[rightIndex] - nums[index] > distance) {
--rightIndex;
}
res += (rightIndex - index);//则以index为一端,距离不超过distance的个数就是rightIndex - index
}
return res;
}
};