The distance of a pair of integers a
and b
is defined as the absolute difference between a
and b
.
Given an integer array nums
and an integer k
, return the kth
smallest distance among all the pairs nums[i]
and nums[j]
where 0 <= i < j < nums.length
.
Example 1:
Input: nums = [1,3,1], k = 1 Output: 0 Explanation: Here are all the pairs: (1,3) -> 2 (1,1) -> 0 (3,1) -> 2 Then the 1st smallest distance pair is (1,1), and its distance is 0.
Example 2:
Input: nums = [1,1,1], k = 2 Output: 0
Example 3:
Input: nums = [1,6,1], k = 3 Output: 5
题目:给定一个数组,求第k个最小距离。
思路一:1,brute force+桶排序,因为0<=nums[i]<=1000000.
代码:
class Solution {
public:
int smallestDistancePair(vector& nums, int k) {
vector record(1000000, 0);
for(int i = 0; i < nums.size()-1; i++){
for(int j = i+1; j < nums.size(); j++){
record[abs(nums[j]-nums[i])]++;
}
}
for(int i = 0; i < record.size(); i++){
if(record[i] >= k) return i;
k -= record[i];
}
return -1;
}
};
time: O(N^2).
超时了,我也不知道为什么别人可以过,我这就超时T_T。再换方法吧
思路二:BFS方法。先将数组排序,然后每相邻两个的距离进priority_queue,queue中保存三个信息{nums[end]和nums[start]距离, end, start},按从小到大排序。每次pop出一个,将前一个指针start向前移动一位。更新距离值和i值后再存入queue中。我记得leetcode中还有一道用这个思路的题,忘记是哪道了~
代码:
class Solution {
public:
struct cmp{
bool operator()(vector& a, vector& b){
return a >= b;
}
};
int smallestDistancePair(vector& nums, int k) {
sort(nums.begin(), nums.end());
priority_queue, vector>, cmp> q;
for(int i = 1; i < nums.size(); i++){
q.push({nums[i]-nums[i-1], i, i-1});
}
for(int i = k; i > 1; i--){
int dis = q.top()[0], end = q.top()[1], start = q.top()[2];
q.pop();
if(start > 0) q.push({nums[end]-nums[start-1], end, start-1});
}
return q.top()[0];
}
};
time: O(N*logN), space:O(max(N, k))
明明时间复杂度不高,但还是超时了,估计是priority_queue的开销太大了。
思路三:二分法,说实话这类的题如果不是做的很熟很难想到二分法。至少我只想到前两种超时的方法:-(。将数组排序,找出最大距离,初始化最小和最大距离。每次取中间距离mid,计算每个元素距离小于等于mid值的元素值总和,如果比k大,取左半部分。比k小,则距离需增大取右半部分。注意在取左半部分的时候为使得最后求出的距离肯定是数组中真实存在的距离,需要end = mid, 不能end = mid-1。
代码:
class Solution {
public:
int smallestDistancePair(vector& nums, int k) {
sort(nums.begin(), nums.end());
int left = 0, right = nums.back() - nums[0];
while(left < right){
int mid = left + (right - left) / 2, n = 0;
for(int i = 0; i < nums.size()-1; i++){
int p = upper_bound(nums.begin()+i, nums.end(), nums[i]+mid) - nums.begin();
if(p < 0) p = nums.size();
n += p-i-1;
}
if(n >= k) right = mid;
else left = mid+1;
}
return left;
}
};
time:O(NlogN), space:O(1)
看,明明也是NlogN的时间复杂度,为啥这个不超时,二分法的logN了不起啊?!priority_queue排序也是logN啊~~~。嗯……纯属没想到最优算法的抱怨之词,堆排序底层实现消耗还是比二分法大的多