力扣第719题 找出第 K 小的数对距离 二分 双指针解法 c++ 时间 超100%用户
题目
困难
数对
(a,b)由整数a和b组成,其数对距离定义为a和b的绝对差值。给你一个整数数组
nums和一个整数k,数对由nums[i]和nums[j]组成且满足0 <= i < j < nums.length。返回 所有数对距离中 第k小的数对距离。
示例 1:
输入:nums = [1,3,1], k = 1 输出:0 解释:数对和对应的距离如下: (1,3) -> 2 (1,1) -> 0 (3,1) -> 2 距离第 1 小的数对是 (1,1) ,距离为 0 。
示例 2:
输入:nums = [1,1,1], k = 2 输出:0
示例 3:
输入:nums = [1,6,1], k = 3 输出:5
提示:
n == nums.length2 <= n <= 1040 <= nums[i] <= 1061 <= k <= n * (n - 1) / 2
思路和解题方法
这段代码实现了在给定整数数组
nums中找出第k小的数对距离。
- 首先,我们对数组
nums进行排序,以便后续的二分查找能够有效进行。- 然后,我们初始化最小距离
left为0,最大距离right为数组最后一个元素与第一个元素的差值,也就是数组的整体范围。- 使用二分查找的方法,在最小距离
left和最大距离right之间进行迭代,直到left和right相等。- 在每次迭代中,我们计算中间距离
mid,并统计小于等于中间距离的距离对数量cnt。- 通过使用双指针技巧,我们在数组中遍历每个元素,并通过移动指针
j来找出满足nums[j] - nums[i] <= mid的元素对。然后,我们统计距离小于等于mid的距离对数量,即j - i - 1。- 根据距离对数量
cnt与目标k的大小关系,调整查找范围。如果cnt < k,说明第k小的数对距离应该在右半部分,因此更新left = mid + 1;如果cnt >= k,说明第k小的数对距离应该在左半部分,因此更新right = mid。- 最后,当
left和right相等时,循环结束,最小的距离就是left,返回它即可。总体而言,该算法通过二分查找和双指针技巧,找出了数组中第
k小的数对距离。通过优化,代码变得更加简洁和高效。
复杂度
时间复杂度:
O(nlogn + nlogm)
时间复杂度为O(nlogn + nlogm)
对数组进行排序:使用了快速排序算法,其时间复杂度为O(nlogn)。
二分查找:每次循环都将查找范围减半,因此最多需要log₂(right - left)次迭代。在每次迭代中,需要遍历一次数组来统计距离小于等于中间距离的距离对数量。因此,对于每次迭代,时间复杂度是O(n)。
综上所述,总的时间复杂度为O(nlogn + nlogm),其中n是数组nums的长度,m是nums中的最大值和最小值的差异。
空间复杂度
O(1)
空间复杂度为O(1),只使用了常数级别的额外空间。
c++ 代码
class Solution {
public:
int smallestDistancePair(vector<int>& nums, int k) {
// 对数组进行排序
sort(nums.begin(), nums.end());
// 初始化最小距离和最大距离
int left = 0, right = nums.back() - nums.front(), n = nums.size();
// 二分查找
while (left < right) {
// 计算中间距离
int mid = left + (right - left) / 2;
// 统计小于等于中间距离的距离对数量
int cnt = 0, j = 0;
for (int i = 0; i < n; i++) {
// 移动指针j,使得nums[j] - nums[i] <= mid
while (j < n && nums[j] - nums[i] <= mid) ++j;
// 统计距离小于等于mid的距离对数量
cnt += j - i - 1;
}
// 根据距离对数量与k的大小关系,不断调整范围
if (cnt < k) left = mid + 1;
else right = mid;
}
// 返回最小距离
return left;
}
};
觉得有用的话可以点点赞,支持一下。
如果愿意的话关注一下。会对你有更多的帮助。
每天都会不定时更新哦 >人< 。

浙公网安备 33010602011771号