【问题标题】:2d coordinates closest to origin最接近原点的二维坐标
【发布时间】:2012-07-28 16:06:44
【问题描述】:

我正在查看以下面试问题:

给定 2d 坐标,找到离坐标最近的 k 个点 起源。提出一种存储点的数据结构和获取k个点的方法。还要指出代码的复杂性。

我想出的解决方案是将二维点保存在一个数组中。对于前k个点,找到每个点到原点的距离并建立一个最大堆。对于剩余的点,计算与原点的距离,比如 dist。如果 dist 大于堆的最顶部元素,则将堆的最顶部元素更改为 dist 并运行heapify() 过程。

这需要O(k) 来构建堆,O((n-k)log k) 用于heapify() 过程,因此总复杂度 = O(n log k)

谁能推荐一个更好的数据结构和/或方法,效率也可能更高?

编辑

其他一些数据结构在这里有用吗?

【问题讨论】:

  • 你实际上可以在时间 O(n) 和空间 O(k) 中做到这一点,其中 k 是你想要的最近点的数量,通过使用一个非常聪明的技巧:stackoverflow.com/questions/9202315/…跨度>
  • 我在徘徊你如何设计数据结构来返回点,即返回可能是一对的集合,但不是数组或距离。

标签: algorithm data-structures performance


【解决方案1】:

你要找的是partial sorting

我认为最好的方法是将所有内容放入未排序的数组中,然后使用修改后的就地快速排序,忽略索引完全高于或完全低于k 的分区,并使用与原点的距离作为比较。

来自上述维基百科文章的伪代码:

function quickfindFirstK(list, left, right, k)
     if right > left
         select pivotIndex between left and right
         pivotNewIndex := partition(list, left, right, pivotIndex)
         if pivotNewIndex > left + k  // new condition
             quickfindFirstK(list, left, pivotNewIndex-1, k)
         if pivotNewIndex < left + k
             quickfindFirstK(list, pivotNewIndex+1, right, k+left-pivotNewIndex-1)

执行后,这会将最小的k 项留在第一个k 位置,但不按顺序排列。

【讨论】:

    【解决方案2】:

    我会为此使用订单统计信息。
    请注意,我们使用修改后的SELECT,它使用与原点的距离作为比较函数。

    • 将元素存储在数组A中,第一个元素是A[1],最后一个元素是A[n]
    • 运行SELECT(A,1,n,k) 以查找最接近原点的kth 元素。
    • 返回元素A[1..k]

    SELECT 的好处之一是它对输入进行分区, 以便将最小的k-1 元素留给A[k]

    因此将元素存储在数组中是O(n)
    运行SELECTO(n)
    返回请求的元素是O(1)

    【讨论】:

    • (1) SELECT 在最坏的情况下需要 O(n^2) 时间。 (2) 不需要上面的第 3 步,因为我需要所有离原点最近的 k 点,但算法不需要修改。
    • 我注意到您向 CLRS 提出了一个问题。您可以在那里看到在 O(n) 最坏情况下运行的 SELECT 的非随机版本。它使用中位数的中位数。
    【解决方案3】:

    我用所谓的“部分排序”http://tzutalin.blogspot.sg/2017/02/interview-type-questions-minqueue.html为你写了一个简单的版本

    public static void main(String[] args) {
        Point[] points = new Point[7];
        points[0] = new Point(0, 0);
        points[1] = new Point(1, 7);
        points[2] = new Point(2, 2);
        points[3] = new Point(2, 2);
        points[4] = new Point(3, 2);
        points[5] = new Point(1, 4);
        points[6] = new Point(1, 1);
        int k = 3;
        qSelect(points, k - 1);
        for (int i = 0; i < k; i++) {
            System.out.println("" + points[i].x + "," + points[i].y);
        }
        // Output will be
        //        0,0
        //        1,1
        //        2,2
    }
    
    // in-place qselect and zero-based
    static void qSelect(Point[] points, int k) {
        int l = 0;
        int h = points.length - 1;
        while (l <= h) {
            int partionInd = partition(l, h, points);
            if (partionInd == k) {
                return;
            } else if (partionInd < k) {
                l = partionInd + 1;
            } else {
                h = partionInd - 1;
            }
        }
    }
    
    static int partition(int l, int h, Point[] points) {
        // Random can be better
        // int p = l + new Random.nextInt(h - l + 1);
        int p = l + (h - l) / 2;
        int ind = l;
        swap(p, h, points);
        Point comparePoint = points[h];
        for (int i = l; i < h; i++) {
            if (points[i].getDistFromCenter() < comparePoint.getDistFromCenter()) {
                swap(i, ind, points);
                ind++;
            }
        }
        swap(ind, h, points);
        return ind;
    }
    
    static void swap(int i, int j, Point[] points) {
        Point temp = points[i];
        points[i] = points[j];
        points[j] = temp;
    }
    

    【讨论】:

      猜你喜欢
      • 2019-04-14
      • 1970-01-01
      • 2014-09-07
      • 1970-01-01
      • 2015-11-16
      • 2019-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多