每日算法系列【LeetCode 719】找出第 k 小的距离对

简介: 每日算法系列【LeetCode 719】找出第 k 小的距离对

题目描述

给定一个整数数组,返回所有数对之间的第 k 个最小距离。一对 (A, B) 的距离被定义为 A 和 B 之间的绝对差值。

示例1

输入:
nums = [1,3,1]
k = 1
输出:
0
解释:
所有数对如下:
(1,3) -> 2
(1,1) -> 0
(3,1) -> 2
因此第 1 个最小距离的数对是 (1,1),它们之间的距离为 0。

提示

  • 2 <= len(nums) <= 10000.
  • 0 <= nums[i] < 1000000.
  • 1 <= k <= len(nums) * (len(nums) - 1) / 2.

题解

注意到这题  比较大,所以不能算出所有的数对差值,然后排序,这样时间复杂度就是  了。

直觉上应该先给数组从小到大排个序,那么差值最小值就是 0 ,最大值就是  ,答案肯定也就在这个区间里了。

那么我们可以从最大的差值开始,看是否有数对满足这个差值,并且这个差值还得是第  小的。对于差值  ,如果它是第  小的,说明所有数对中差值小于等于  的数对个数  一定大于等于  。因为如果第  小的差值只有一个数对满足,那么  ,否则的话就有多个数对差值都是  ,那就有  。于是我们找到第一个满足  的差值就行了,再加 1 就是最终的答案。

那么怎么求小于等于  的数对个数  呢?因为排过序了,所以可以采用双指针的方法,初始时  ,对于每个右指针  ,我们移动左指针  ,直到  。那么最终  就是以  作为较大数的数对个数。因为两个指针都是向右移动的,所以每次计算个数只需要  的时间复杂度。

所以这个方法最终总的时间复杂度为  ,因为最大差值  还是太大,所以还是没有办法直接遍历。

又注意到随着  的减小,  也是单调减小的,所以可以二分寻找  。如果  ,那么说明答案小于等于  ,于是令  。如果  ,那么说明答案一定大于  ,于是令  ,最终答案就是  。

这样二分优化之后,最终的时间复杂度为  ,可以接受。

代码

c++

class Solution {
public:
    int smallestDistancePair(vector<int>& nums, int k) {
        int n = nums.size();
        sort(nums.begin(), nums.end());
        int l = 0, r = nums[n-1]-nums[0];
        while (l < r) {
            int m = (l + r) / 2;
            if (count(m, nums) >= k) r = m;
            else l = m + 1;
        }
        return l;
    }
    int count(int K, vector<int>& nums) {
        int cnt = 0, l = 0, n = nums.size();
        for (int r = 0; r < n; ++r) {
            while (l < r && nums[r]-nums[l] > K) {
                l++;
            }
            cnt += r - l;
        }
        return cnt;
    }
};

python

class Solution:
    def smallestDistancePair(self, nums: List[int], k: int) -> int:
        n = len(nums)
        nums.sort()
        def count(K: int) -> int:
            cnt, l = 0, 0
            for r in range(n):
                while l < r and nums[r]-nums[l] > K:
                    l += 1
                cnt += r - l
            return cnt
        l, r = 0, nums[-1]-nums[0]
        while l < r:
            m = (l + r) // 2
            if count(m) >= k:
                r = m
            else:
                l = m + 1
        return l
相关文章
|
1月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
39 0
|
17天前
|
存储 算法 Java
leetcode算法题-有效的括号(简单)
【11月更文挑战第5天】本文介绍了 LeetCode 上“有效的括号”这道题的解法。题目要求判断一个只包含括号字符的字符串是否有效。有效字符串需满足左括号必须用相同类型的右括号闭合,并且左括号必须以正确的顺序闭合。解题思路是使用栈数据结构,遍历字符串时将左括号压入栈中,遇到右括号时检查栈顶元素是否匹配。最后根据栈是否为空来判断字符串中的括号是否有效。示例代码包括 Python 和 Java 版本。
|
1月前
|
算法
每日一道算法题(Leetcode 20)
每日一道算法题(Leetcode 20)
27 2
|
3月前
|
算法 Java
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
52 6
|
3月前
|
人工智能 算法 Java
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
50 1
|
3月前
|
存储 算法 Java
LeetCode经典算法题:预测赢家+香槟塔java解法
LeetCode经典算法题:预测赢家+香槟塔java解法
61 1
|
3月前
|
存储 算法 Java
LeetCode经典算法题:二叉树遍历(递归遍历+迭代遍历+层序遍历)以及线索二叉树java详解
LeetCode经典算法题:二叉树遍历(递归遍历+迭代遍历+层序遍历)以及线索二叉树java详解
80 0
|
3月前
|
算法 Java
LeetCode初级算法题:子数组最大平均数+二叉树的最小深度+最长连续递增序列+柠檬水找零
LeetCode初级算法题:子数组最大平均数+二叉树的最小深度+最长连续递增序列+柠檬水找零
43 0
|
3月前
|
算法 Java
LeetCode初级算法题:环形链表+排列硬币+合并两个有序数组java解法
LeetCode初级算法题:环形链表+排列硬币+合并两个有序数组java解法
55 0
|
3月前
|
存储 算法 Java
LeetCode初级算法题:两数之和+斐波拉契数列多种java解法
LeetCode初级算法题:两数之和+斐波拉契数列多种java解法
39 0
下一篇
无影云桌面