给定一个整数数组,返回所有数对之间的第 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
.
题目大意:
本题是给出一个数组,每两个数之间的差值定义为距离,找出这个数组中所有距离中的第k小的值。
解题思路:
本题可以用二分查找的思想,二分查找最初是用来找一个数,在本题中我们可以用来找差值,先明确我们要找的目标值:一个距离target,数组的所有距离中小于target的个数为k-1。首先将数组排序,找到距离的最大值end和最小值start。然后进行二分查找:
若这个数组中距离小于等于mid的距离的个数大于k,则说明这个mid比我们的目标值大,我们在左半边继续查找;
若这个数组中距离小于等于mid的距离的个数小于k,则说明这个mid比我们的目标值小,我们在右半边继续查找;
然后问题就落在了确定有多少个距离小于等于mid。在这里我们可以用滑动窗口的思想。一个窗口就代表一个区间,因为数组被我们排序过了,所以当一个区间的起点和终点的距离小于等于mid时,区间中每个数与终点的距离都小于等于mid。那么我们就先固定区间的右端,让左端逐渐向右端靠近,每当左端与右端的距离小于等于mid时,将区间的长度累加起来。代码如下:
class Solution {
public:
int co(vector<int>& nums,int target)
{
int left=0;
int res=0;
//固定右端
for(int right=0;right<nums.size();right++)
{
//若左右端距离太大的话,让左端向右端滑近
while(nums[right]-nums[left]>target)
left++;
//将区间长度累加起来
res+=right-left;
}
return res;
}
int smallestDistancePair(vector<int>& nums, int k) {
sort(nums.begin(),nums.end());
int start=0;
int end=nums[nums.size()-1]-nums[0];
//二分查找
while(start+1<end)
{
int mid=(end-start)/2+start;
if(co(nums,mid)>=k)
end=mid;
else
start=mid;
}
//再次确定结果
if(co(nums,start)>=k)
return start;
else
return end;
}
};