leetcode-找出第 K 小的数对距离

183 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第21天,点击查看活动详情

题目描述

数对 (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.length
  • 2 <= n <= 104
  • 0 <= nums[i] <= 106
  • 1 <= k <= n * (n - 1) / 2

思路

今天的题目难度是困难,确实挺难的。一开始的思路是,先对数组排序,然后求前缀和,然后数对的距离就是前缀和的差值,不过好像也无法带来什么帮助。
看了题解的二分+双指针的方法,记录一下。
先对数组排序,数对距离是绝对值,所以范围肯定在[0, nums[len-1]-nums[0]]之内。
采取二分的方式,对于mid,校验距离小于等于mid的数对数量,如果小于k,mid肯定不满足,接下来left = mid + 1,如果大于,mid可以作为备选,继续向左校验,right = mid。
求小于等于mid的数对数量,可以采用双指针的方法,固定住每个小指针i,大指针j向后走直到满足nums[j] - num[i] > k 或者 j == len,此时,数对的数量为j-i-1。
然后小指针i从0到len-2(因为最后至少要留1个位置给大指针j)遍历,对于每个i,计算出满足的数量,然后求和就可以整体求出数组nums中满足小于等于mid的数对的数量了。

Java版本代码

class Solution {
    public int smallestDistancePair(int[] nums, int k) {
        Arrays.sort(nums);
        int left = 0, right = nums[nums.length-1] - nums[0];
        while (left < right) {
            int mid = left + ((right - left)>>1);
            int count = count719(nums, mid);
            if (count < k) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }

    private static int count719(int[] nums, int val) {
        int count = 0, len = nums.length;
        for (int i = 0, j = 1; i < len - 1; i++) {
            while (j < len && nums[j] - nums[i] <= val) {
                j++;
            }
            count += j - i - 1;
        }
        return count;
    }
}