跳转至

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

题目描述

数对 (a,b) 由整数 ab 组成,其数对距离定义为 ab 的绝对差值。

给你一个整数数组 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

解法

方法一:排序 + 二分查找

先对 $nums$ 数组进行排序,然后在 $[0, nums[n-1]-nums[0]]$ 范围内二分枚举数对距离 $dist$,若 $nums$ 中数对距离小于等于 $dist$ 的数量 $cnt$ 大于等于 $k$,则尝试缩小 $dist$,否则尝试扩大 $dist$。

时间复杂度 $O(nlogn×logm)$,其中 $n$ 表示 $nums$ 的长度,$m$ 表示 $nums$ 中两个数的最大差值。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Solution:
    def smallestDistancePair(self, nums: List[int], k: int) -> int:
        def count(dist):
            cnt = 0
            for i, b in enumerate(nums):
                a = b - dist
                j = bisect_left(nums, a, 0, i)
                cnt += i - j
            return cnt

        nums.sort()
        return bisect_left(range(nums[-1] - nums[0]), k, key=count)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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) >> 1;
            if (count(mid, nums) >= k) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        return left;
    }

    private int count(int dist, int[] nums) {
        int cnt = 0;
        for (int i = 0; i < nums.length; ++i) {
            int left = 0, right = i;
            while (left < right) {
                int mid = (left + right) >> 1;
                int target = nums[i] - dist;
                if (nums[mid] >= target) {
                    right = mid;
                } else {
                    left = mid + 1;
                }
            }
            cnt += i - left;
        }
        return cnt;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
    int smallestDistancePair(vector<int>& nums, int k) {
        sort(nums.begin(), nums.end());
        int left = 0, right = nums.back() - nums.front();
        while (left < right) {
            int mid = (left + right) >> 1;
            if (count(mid, k, nums) >= k)
                right = mid;
            else
                left = mid + 1;
        }
        return left;
    }

    int count(int dist, int k, vector<int>& nums) {
        int cnt = 0;
        for (int i = 0; i < nums.size(); ++i) {
            int target = nums[i] - dist;
            int j = lower_bound(nums.begin(), nums.end(), target) - nums.begin();
            cnt += i - j;
        }
        return cnt;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
func smallestDistancePair(nums []int, k int) int {
    sort.Ints(nums)
    n := len(nums)
    left, right := 0, nums[n-1]-nums[0]
    count := func(dist int) int {
        cnt := 0
        for i, v := range nums {
            target := v - dist
            left, right := 0, i
            for left < right {
                mid := (left + right) >> 1
                if nums[mid] >= target {
                    right = mid
                } else {
                    left = mid + 1
                }
            }
            cnt += i - left
        }
        return cnt
    }
    for left < right {
        mid := (left + right) >> 1
        if count(mid) >= k {
            right = mid
        } else {
            left = mid + 1
        }
    }
    return left
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function smallestDistancePair(nums: number[], k: number): number {
    nums.sort((a, b) => a - b);
    const n = nums.length;
    let left = 0,
        right = nums[n - 1] - nums[0];
    while (left < right) {
        let mid = (left + right) >> 1;
        let count = 0,
            i = 0;
        for (let j = 0; j < n; j++) {
            // 索引[i, j]距离nums[j]的距离<=mid
            while (nums[j] - nums[i] > mid) {
                i++;
            }
            count += j - i;
        }
        if (count >= k) {
            right = mid;
        } else {
            left = mid + 1;
        }
    }
    return left;
}

评论