当前位置: 首页 > 知识库问答 >
问题:

查找第K个最小对距离-分析

周伟泽
2023-03-14

问题:

这是LeetCode的问题:

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

例子:

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.

我的问题

我用一个简单的方法解决了它O(n^2),基本上我找到所有的距离并对其进行排序,然后找到第k个最小的。现在这是一个更好的解决方案。这不是我的代码,我在leetcode的讨论论坛上找到了它。但是我很难理解代码的关键部分。

下面的代码基本上是在做一个二分搜索法。< code >低是最小距离,< code >高是最大距离。像通常的二分搜索法一样计算一个< code>mid。然后,它< code>countPairs(a,mid)查找绝对差小于或等于< code>mid的对的数量。然后相应地调整< code >低和< code >高。

但是为什么二分搜索法结果一定是距离之一呢?起初,从数组中得到< code>low和< code>high,但是< code>mid是由它们计算的,它可能不是距离。最后,我们返回< code>low,其值在基于< code>mid 1的二分搜索法期间发生变化。为什么< code>mid 1保证是距离之一?

class Solution {
    // Returns index of first index of element which is greater than key
    private int upperBound(int[] a, int low, int high, int key) {
        if (a[high] <= key) return high + 1;
        while (low < high) {
            int mid = low + (high - low) / 2;
            if (key >= a[mid]) {
                low = mid + 1;
            } else {
                high = mid;
            }
        }
        return low;
    }

    // Returns number of pairs with absolute difference less than or equal to mid.
    private int countPairs(int[] a, int mid) {
        int n = a.length, res = 0;
        for (int i = 0; i < n; i++) {
            res += upperBound(a, i, n - 1, a[i] + mid) - i - 1;
        }
        return res;
    }

    public int smallestDistancePair(int a[], int k) {
        int n = a.length;
        Arrays.sort(a);

        // Minimum absolute difference
        int low = a[1] - a[0];
        for (int i = 1; i < n - 1; i++)
            low = Math.min(low, a[i + 1] - a[i]);

        // Maximum absolute difference
        int high = a[n - 1] - a[0];

        // Do binary search for k-th absolute difference
        while (low < high) {
            countPairs(a, mid)
            if (countPairs(a, mid) < k)
                low = mid + 1;
            else
                high = mid;
        }

        return low;
    }
}

共有2个答案

齐琦
2023-03-14

出于兴趣,我们可以在O(n log n m log m)时间内解决这个问题,其中m是范围,使用快速傅里叶变换

首先对输入进行排序。现在考虑一下,数字之间每个可达到的距离都可以通过从另一个数字中减去一个差前缀和来实现。例如:

input:            1 3 7
diff-prefix-sums:  2 6
difference between 7 and 3 is 6 - 2

现在,让我们将总计(最右边的前缀总和)添加到等式的每一侧:

ps[r] - ps[l]       = D
ps[r] + (T - ps[l]) = D + T

让我们列出差异:

1 1 3
 0 2

前缀和:

p     => 0 0 2
T - p => 2 2 0  // 2-0, 2-0, 2-2

我们需要有效地确定和排序所有不同的可实现的差异的计数。这类似于将系数为< code>[1,0,2]的多项式乘以系数为< code>[2,0,0]的多项式(我们不需要第二组中的零系数,因为它仅生成小于或等于< code>T的度数),这可以通过快速傅立叶变换在< code>m log m时间内完成,其中< code>m是度数。

合成系数将为:

  1 0 2
* 
  2 0 0
=> 
  x^2 + 2
*
  2x^2

= 2x^4 + 4x^2

=> 2 0 4 0 0

我们丢弃低于T的度数,并显示我们排序的结果:

2 * 4 = 2 * (T + 2) => 2 diffs of 2
4 * 2 = 4 * (T + 0) => 4 diffs of 0

我们多计算了0的差异。也许有人会建议,有一种简便的方法来计算零超额计数。我花了一些时间,但还没有分辨出一个。

在任何情况下,使用不相交重复计数可以很容易地获得零差异的计数,这允许我们仍然返回O(n log n m m log m)总时间中的k个差值。

施飞昂
2023-03-14

这种类型的二进制搜索将找到第一个值 x,其计数对(a,x)

因此,当函数以最终值低终止时,我们知道当距离从low-1变为低时,对数会发生变化,因此必须存在一对距离较低的对。

例如,假设我们的目标是100,并且知道:

countPairs(a,9) = 99
countPairs(a,10) = 100

必须有一对距离正好为10的数字,因为如果没有这样的数字对,那么距离小于或等于10的数字对的数量将与距离小于或大于9的数字对数量相同。

请注意,这只适用于循环运行,直到测试间隔完全耗尽。如果代码使用了提前终止条件,如果找到准确的目标值,则会退出循环,那么它可能会返回错误的答案。

 类似资料:
  • 假设我有一个包含整数的数组。 如何找到大小的子集,使得子集中所有整数对之间的距离,我的意思是它们在最远的距离。 示例:数组和, ,最小距离为10和6之间的<错误的子集: ,最小距离为 ,最小距离为 我想到了一个解决办法: 1) 排序数组2)选择一个[0],现在在数组中查找ceil(a[0])=Y。。。。然后ceil(Y

  • 我有一个多边形类型的几何体,我正在计算一个点的最小距离可能在多边形几何体内部(由360个点组成,作为闭合几何体)或多边形几何体外部。使用postgis的ST_distance方法,当点在几何体外部时,我得到精确的距离,但如果点在几何体内部,则得到0作为距离,我想要与多边形几何体最近点的点之间的最小距离,无论该点位于几何体内部还是外部。

  • 题目描述 输入n个整数,输出其中最小的k个。 分析与解法 解法一 要求一个序列中最小的k个数,按照惯有的思维方式,则是先对这个序列从小到大排序,然后输出前面的最小的k个数。 至于选取什么的排序方法,我想你可能会第一时间想到快速排序(我们知道,快速排序平均所费时间为n*logn),然后再遍历序列中前k个元素输出即可。因此,总的时间复杂度:O(n * log n)+O(k)=O(n * log n)。

  • 问题内容: 我在此站点上找到此代码以查找第二大数字: 是否可以修改此代码以找到第二个 最小的 数字?所以举个例子 问题答案: 确实可以修改该函数以找到第二个最小的函数: 旧版本依赖于Python 2实施细节,该细节始终排在其他任何东西之前(因此测试为“较小”);我取代了使用作为前哨,为无穷大总是测试, 更大的 比任何其它号码。理想情况下,应该使用原始函数代替原始函数,以免与其他Python实现可能

  • 例如,我有两个实体列表和一个测量它们之间距离的函数。假设是姓名和电子邮件。在下面的表格中,我测量了每封电子邮件到每个名字的距离。 现在我想在名称中找到每个电子邮件的最小距离对。但是,请注意,如果两封电子邮件具有相同的最小距离名称候选人,则赢得距离最小的人。在这种情况下,另一个电子邮件应该选择第二接近的候选名称,并再次检查。 因此,在这种情况下,结果应为: 解释表: 速度很重要。。它可以以数据帧或d

  • 一个网站的问题:实现一个Java函数,在一个数组中找到两个彼此距离最小的数字。函数应该返回第一个数字的索引。 null