力扣 719. 找出第 K 小的数对距离

题目来源:https://leetcode.cn/problems/find-k-th-smallest-pair-distance/

大致题意:
给一个数组 nums,定义数对距离为 nums[j] - nums[i] 的绝对值,找出数组所有数对中第 k 小的数对距离

思路

  1. 对数组排序,那么数对距离的取值范围为 [ 0, nums[n - 1] - nums[0] ]
  2. 于是在数对距离范围中二分搜索第 k 小的数对距离

对于当前数对距离 mid,枚举求出小于等于 mid 的数对个数 count,若 k > count,表示当前二分中值小于目标值,更新左边界为 mid + 1;反之,表示当前二分中值大于等于目标值,更新右边界为 mid - 1

枚举时可以使用双指针优化,初始时两个指针都为 0,右指针逐步增加,统计以当前右指针为右边界的数对差小于mid的数对个数。
在左指针小于右指针且当前右指针处元素减去左指针处元素的数对差大于 mid时,更新左指针。

  1. 最后二分搜索的左边界值即为目标值

二分过程中,枚举到目标值时会更新右边界,让右边界的值小于目标值,也就是说此时二分边界内的值都小于目标值,在之后的枚举过程中会一直更新左边界,直至左边界大于右边界,这时左边界的值也就是目标值了

代码:

public int smallestDistancePair(int[] nums, int k) {
        // 排序
        Arrays.sort(nums);
        int n = nums.length;
        // 初始化二分边界
        int l = 0;
        int r = nums[n - 1] - nums[0];
        // 二分
        while (l <= r) {
            int mid = (l + r) >> 1;
            // 初始化双指针
            int idx1 = 0;
            int idx2 = 0;
            // 差小于等于当前二分中值的数对数目
            int count = 0;
            while (idx2 < n) {
                // 若当前数对差大于二分中值,左边界右移
                while (idx1 < idx2 && nums[idx2] - nums[idx1] > mid) {
                    idx1++;
                }
                // idx2 - idx1 即为以 idx2 为右边界的数对差小于二分中值的数对个数
                count += idx2 - idx1;
                // 更新右边界
                idx2++;
            }
            // 若 k 大于 所有数对中小于当前二分中值的数对数目,表示当前二分中值小于目标值,更新左边界
            if (k > count) {
                l = mid + 1;
            } else {    // 否则,表示当前二分中值大于等于目标值,更新右边界
                r = mid - 1;
            }
        }
        /*
        二分过程中,枚举到目标值时会更新右边界,让右边界的值小于目标值,也就是说
        此时二分边界内的值都小于目标值,在之后的枚举过程中会一直更新左边界,直至左边界大于右边界
        这时左边界的值也就是目标值了
         */
        return l;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三更鬼

谢谢老板!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值