Given an integer array, return the k-th smallest distance among all the pairs. The distance of a pair (A, B) is defined as the absolute difference between A and B.

Example 1:

Input:
nums = [1,3,1]
k = 1
Output: 0
Explanation:
Here are all the pairs:
(1,3) -> 2
(1,1) -> 0
(3,1) -> 2
Then the 1st smallest distance pair is (1,1), and its distance is 0.

Note:

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

这道题给了我们一个数组,让我们找第k小的数对儿距离,数对儿距离就是任意两个数字之间的绝对值差。那么我们先来考虑最暴力的解法,是不是就是遍历任意两个数字,算出其绝对值差,然后将所有距离排序,取第k小的就行了。But,OJ 摇着头说图样图森破。但是我们可以在纯暴力搜索的基础上做些优化,从而让 OJ 说 YES。那么下面这种利用了桶排序的解法就是一种很好的优化,题目中给了数字的大小范围,不会超过一百万,所以我们就建立一百万个桶,然后还是遍历任意两个数字,将计算出的距离放到对应的桶中,这里桶不是存的具体距离,而是该距离出现的次数,桶本身的位置就是距离,所以我们才建立了一百万个桶。然后我们就可以从0开始遍历到一百万了,这样保证了我们先处理小距离,如果某个距离的出现次数大于等于k了,那么我们返回这个距离,否则就用k减去这个距离的出现次数,参见代码如下:

解法一:

class Solution {
public:
int smallestDistancePair(vector<int>& nums, int k) {
int n = nums.size(), N = ;
vector<int> cnt(N, );
for (int i = ; i < n; ++i) {
for (int j = i + ; j < n; ++j) {
++cnt[abs(nums[i] - nums[j])];
}
}
for (int i = ; i < N; ++i) {
if (cnt[i] >= k) return i;
k -= cnt[i];
}
return -;
}
};

上面的解法虽然逃脱了 OJ 的魔掌,但也仅仅是险过,并不高效。我们来看一种基于二分搜索的解法。这道题使用的二分搜索法是博主归纳总结帖 LeetCode Binary Search Summary 二分搜索法小结 中的第四种,即二分法的判定条件不是简单的大小关系,而是可以抽离出子函数的情况,下面我们来看具体怎么弄。我们的目标是快速定位出第k小的距离,那么很适合用二分法来快速的缩小查找范围,然而最大的难点就是如何找到判定依据来折半查找,即如果确定搜索目标是在左半边还是右半边。做过 Kth Smallest Element in a Sorted Matrix 和 Kth Smallest Number in Multiplication Table 这两道题的同学应该对这种搜索方式并不陌生。核心思想是二分确定一个中间数,然后找到所有小于等于这个中间数的距离个数,用其跟k比较来确定折半的方向。具体的操作是,我们首先要给数组排序,二分搜索的起始 left 为0,结束位置 right 为最大距离,即排序后的数字最后一个元素减去首元素。然后进入 while 循环,算出中间值 mid,此外我们还需要两个变量 cnt 和 start,其中 cnt 是记录小于等于 mid 的距离个数,start 是较小数字的位置,均初始化为0,然后我们遍历整个数组,先进行 while 循环,如果 start 未越界,并且当前数字减去 start 指向的数组之差大于 mid,说明此时距离太大了,我们增加减数大小,通过将 start 右移一个,那么 while 循环退出后,就有 i - start 个距离小于等于 mid,将其加入 cnt 中,举个栗子来说:

1    2    3    3    5

start              i

mid = 2

如果 start 在位置0,i在位置3,那么以 nums[i] 为较大数可以产生三个(i - start)小于等于 mid 的距离,[1 3], [2 3], [3 3],这样当i遍历完所有的数字后,所有小于等于 mid 的距离的个数就求出来了,即 cnt。然后我们跟k比较,如果其小于k,那么 left 赋值为 mid+1,反之,则 right 赋值为 mid。最终返回 right 或 left 均可,参见代码如下:

解法二:

class Solution {
public:
int smallestDistancePair(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());
int n = nums.size(), left = , right = nums.back() - nums[];
while (left < right) {
int mid = left + (right - left) / , cnt = , start = ;
for (int i = ; i < n; ++i) {
while (start < n && nums[i] - nums[start] > mid) ++start;
cnt += i - start;
}
if (cnt < k) left = mid + ;
else right = mid;
}
return right;
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/719

类似题目:

Find K Pairs with Smallest Sums

Kth Smallest Element in a Sorted Matrix

Find K Closest Elements

Kth Smallest Number in Multiplication Table

K-th Smallest Prime Fraction

参考资料:

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

https://leetcode.com/problems/find-k-th-smallest-pair-distance/discuss/109077/C++-counting-sort-O(n2)-and-binary-search-O(nlogn)

https://leetcode.com/problems/find-k-th-smallest-pair-distance/discuss/109082/Approach-the-problem-using-the-%22trial-and-error%22-algorithm

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Find K-th Smallest Pair Distance 找第K小的数对儿距离的更多相关文章

  1. [LeetCode] 719. Find K-th Smallest Pair Distance 找第K小的数对儿距离

    Given an integer array, return the k-th smallest distance among all the pairs. The distance of a pai ...

  2. 719. Find K-th Smallest Pair Distance

    Given an integer array, return the k-th smallest distance among all the pairs. The distance of a pai ...

  3. 【leetcode】719. Find K-th Smallest Pair Distance

    题目如下: 解题思路:对于这一类知道上限和下限,求第N位是什么的题目,可以先看看二分查找的方法可不可行.首先对nums进行排序,很显然任意两个元素距离绝对值最小是0,最大是nums[-1] - num ...

  4. [Swift]LeetCode719. 找出第 k 小的距离对 | Find K-th Smallest Pair Distance

    Given an integer array, return the k-th smallest distance among all the pairs. The distance of a pai ...

  5. 【leetcode】668. Kth Smallest Number in Multiplication Table

    题目如下: 解题思路:几乎和[leetcode]719. Find K-th Smallest Pair Distance 的方法一样.只不过一个是减法一个是乘法,还有一点区别是[leetcode]7 ...

  6. 第 k 小的数

    一.寻找两个有序数组的中位数 1.1 问题描述 给定两个大小为 m 和 n 的不同时为空的有序数组 nums1 和 nums2.找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m ...

  7. 算法打基础——顺序统计(找第k小数)

    这次主要是讲如何在线性时间下找n个元素的未排序序列中第k小的数.当然如果\(k=1 or k=n\),即找最大最小 数,线性时间内遍历即可完成,当拓展到一般,如中位数时,相关算法就值得研究了.这里还要 ...

  8. [LeetCode] Find the Derangement of An Array 找数组的错排

    In combinatorial mathematics, a derangement is a permutation of the elements of a set, such that no ...

  9. [Swift]LeetCode668. 乘法表中第k小的数 | Kth Smallest Number in Multiplication Table

    Nearly every one have used the Multiplication Table. But could you find out the k-th smallest number ...

随机推荐

  1. 关于js中promise的面试题。

    核心点promise在生命周期内有三种状态,分别是pending,fulfilled或rejected,状体改变只能是 pending-fulfilled,或者pending-rejected.而且状 ...

  2. 如何使用 RESTClient 调试微信支付接口

    我们知道微信支付使用http协议进行api调用,body 使用xml格式,使用的一般http在线调试工具,无法进行xml数据的post. RESTClient 做的很好,支持各种http 方法,bod ...

  3. bootstrap 模态框(modal)插件使用

    今天用户登陆时,在原网页上弹出新登陆窗口,发现使用的是modal插件,记录下该插件的使用方法,手写强化下. 首先,模态框(modal)是覆盖在父窗体上的子窗体,目的是显示来自一个单独的源的内容,可以在 ...

  4. java基础笔记(4)----数组

    介绍: 数组是一种数据类型,是引用类型,是一块连续的内存空间,用于存储和管理相同类型的多个数据. 定义:-- > 数组的声明方式 先声明,在开辟内存空间--> int [] a; a=ne ...

  5. python+selenium:解决上传文件<input type='file'>标签属性被css的visibility隐藏导致无法定位元素的问题

    要想上传文件,需要找到在HTML中<input type="file" />这个标签,有它就可以利用send_keys上传文件,不过这里的<input>元素 ...

  6. 实现mypwd

    1 学习pwd命令 2 研究pwd实现需要的系统调用(man -k; grep),写出伪代码 3 实现mypwd 4 测试mypwd 提交过程博客的链接 代码如图

  7. 详谈C++虚函数表那回事(一般继承关系)

    沿途总是会出现关于C++虚函数表的问题,今天做一总结: 1.什么是虚函数表: 虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的.简称为V-Table. ...

  8. django模型——数据库(二)

    模型--数据库(二) 实验简介 模型的一些基本操作,save方法用于把对象写入到数据库,objects是模型的管理器,可以使用它的delete.filter.all.order_by和update等函 ...

  9. Python choice() 函数

    Python choice() 函数  Python 数字 描述 choice() 方法返回一个列表,元组或字符串的随机项. 语法 以下是 choice() 方法的语法: import random ...

  10. segmentedControl设置字体和字体颜色问题

    NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:[UIColor blackColor],UITextAttributeT ...