【Leetcode】719. Find K-th Smallest Pair Distance

题目地址:

https://leetcode.com/problems/find-k-th-smallest-pair-distance/

给定一个长 n n n的数组 A A A,给定不等的两个下标 i i i j j j,我们总能算出数对差 ∣ A [ i ] − A [ j ] ∣ |A[i]-A[j]| A[i]A[j]。给定一个正整数 k k k,问第 k k k小的这样的数对差是多少。下标的顺序不同也视为同一数对。

思路是二分答案。若 A A A的最大值是 M M M,最小值是 m m m,则最大的差显然是 M − m M-m Mm,最小差是 0 0 0。我们可以二分答案,每次二分出一个数 x x x,就看一下比它小于等于的数对差有多少个,如果大于等于 k k k个,则说明最终答案不大于 x x x,则收缩右边界到 x x x;否则说明最终答案大于 x x x,则收缩左边界到 x + 1 x+1 x+1。计算比 x x x小于等于的数对差的个数,可以用排序 + 双指针来做。对数组排好序之后,开两个指针 i i i j j j保持 i > j i>j i>j(因为数对不能取重复数),如果数对差大于 x x x了,则右移左指针,直到数对差小于等于或 j = i j=i j=i为止,然后累加 i − j i-j ij(这里 i − j i-j ij是以 A [ i ] A[i] A[i]为较大值的且数对差小于等于 x x x的数对个数)。注意这里不用回退左指针,原因是回退只会导致数对差更大,得不到答案。代码如下:

import java.util.Arrays;

public class Solution {
    
    
    public int smallestDistancePair(int[] nums, int k) {
    
    
        if (nums == null || nums.length == 0) {
    
    
            return 0;
        }
        
        Arrays.sort(nums);
        
        int l = 0, r = nums[nums.length - 1] - nums[0];
        while (l < r) {
    
    
            int m = l + (r - l >> 1);
            // 计算一下小于等于m的数对差的个数
            int count = 0;
            for (int i = 0, j = 0; i < nums.length; i++) {
    
    
                while (j < i && nums[i] - nums[j] > m) {
    
    
                    j++;
                }
                
                count += i - j;
            }
            
            // 如果小于等于m的数对差的个数大于等于k,则收缩右边界,否则收缩左边界
            if (count >= k) {
    
    
                r = m;
            } else {
    
    
                l = m + 1;
            }
        }
        
        return l;
    }
}

时间复杂度 O ( n ( log ⁡ ( M − m ) + n ) ) O(n(\log (M-m) + n)) O(n(log(Mm)+n)) M M M是数组最大值, m m m是数组最小值,空间 O ( 1 ) O(1) O(1)

猜你喜欢

转载自blog.csdn.net/qq_46105170/article/details/113028920
今日推荐