Найти K ближайших точек к точке P в двумерной плоскости

Источник: AMAZON INTERVIEW QUESTION

Учитывая точку P и другие N точек в двухмерном пространстве, найдите K точек из N точек, которые ближайшего до P.

Каков оптимальный способ сделать это?

Эта страница Wiki не дает большой помощи в построении алгоритма. Любые идеи/подходы к людям.

Ответы

Ответ 1

Решение 1 делает кучу размера K и собирает точки с минимальной сложностью O (NLogK).

Решение 2: Возьмите и массируйте размер N и Сортировать по расстоянию. Должен использоваться QuickSort (модификация Hoare). В качестве ответа возьмите первые K баллов. Это слишком сложная задача NlogN, но можно оптимизировать приближение O (N). Если пропустить сортировку ненужных вспомогательных массивов. Когда вы разбиваете массив на 2 подматрицы, вы должны брать только массив, в котором находится индекс Kth. сложность будет: N + N/2 + N/4 +... = O (N).

Решение 3: найдите элемент Kth в массиве результатов и затем создайте все точки меньше. Существует O (N) alghoritm, аналогично поиску медианы.

Примечания: лучше использовать sqr расстояния, чтобы избежать операций sqrt, он будет быстрее, если точка имеет целые координаты.

В качестве ответа на интервью лучше использовать Решение 2 или 3.

Ответ 2

Только для одного запроса...

Поддерживайте heap размер k.

Для каждой точки вычислите расстояние до точки P. Вставьте это расстояние в кучу и удалите максимум из кучи, если размер кучи больше, чем k.

Продолжительность: O(n log k)

Ответ 3

Вы можете использовать дерево KD http://en.wikipedia.org/wiki/K-d_tree для разделения пространства и при условии, что вы сможете постепенно искать соседей, используя двоичный поиск. Преимущество использования этого подхода заключается в том, что он легко масштабируется до онлайн-версии, когда вы получаете точки/запросы во время выполнения один за другим или в пакетах.

Ответ 4

Решение 1

private List<Point> nearestKPoint_1(List<Point> list, final Point center, int k) {
    List<Point> ans = new ArrayList<>();
    PriorityQueue<Point> maxHeap = new PriorityQueue<>(k + 1, new Comparator<Point>() {
        @Override
        public int compare(Point o1, Point o2) {
            return distance(center, o2) - distance(center, o1);
        }
    });
    for (Point p : list) {
        maxHeap.offer(p);
        if (maxHeap.size() > k) {
            maxHeap.poll();
        }
    }
    Iterator<Point> i = maxHeap.iterator();
    while (i.hasNext()) {
        ans.add(i.next());
    }
    return ans;
}

public int distance(Point p1, Point p2) {
    return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}

static class Point {
    int x;
    int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Point point = (Point) o;

        if (x != point.x) return false;
        return y == point.y;
    }

    @Override
    public int hashCode() {
        int result = x;
        result = 31 * result + y;
        return result;
    }
}

Решение 2

private List<Point> nearestKPoint_2(List<Point> list, final Point center, int k) {
    List<Point> ans = new ArrayList<>();
    Distance[] nums = new Distance[list.size()];
    for (int i = 0; i < nums.length; i++) {
        nums[i] = new Distance(distance(center, list.get(i)), i);
    }
    quickSelect(nums, k);
    for (int i = 0; i < k; i++) {
        ans.add(list.get(nums[i].i));
    }
    return ans;
}

private void quickSelect(Distance[] nums, int k) {
    int start = 0, end = nums.length - 1;
    while (start < end) {
        int p = partition(nums, start, end);
        if (p == k) {
            return;
        } else if (p < k) {
            start = p + 1;
        } else {
            end = p - 1;
        }
    }
}
private int partition(Distance[] nums, int start, int end) {
    Distance pivot = nums[start];
    int i = start, j = end + 1;
    while (true) {
        while (i < end && nums[++i].compareTo(pivot) < 0);
        while (j > start && nums[--j].compareTo(pivot) > 0);
        if (i >= j) {
            break;
        }
        swap(nums, i, j);
    }
    swap(nums, start, j);
    return j;
}

private void swap(Distance[] nums, int i, int j) {
    Distance tmp = nums[i];
    nums[i] = nums[j];
    nums[j] = tmp;
}

class Distance implements Comparable<Distance> {
    int d;
    int i;

    public Distance(int d, int i) {
        this.d = d;
        this.i = i;
    }

    @Override
    public int compareTo(Distance o) {
        return this.d - o.d;
    }
}

Ответ 5

// point_type pt, length_sq(p) { return pt[0] * pt[0] + pt[1] * pt[1]}
// std::vector<point_type> points to search.
// The algorithm should recursion depth to 
//       O(k * log(points.size())), and
// running time to O(points.size()).

std::nth_element(
               points.begin(),
               points.begin() + k,
               points.end(),
               [&pt](point_type const & a)
               {
                    return length_squared(a - pt);
               });

// points[0], ... , points[k - 1] are the closest points to pt

Ответ 6

class Solution {
   public int[][] kClosest(int[][] points, int K) {
        double [] combinationArr = new double[points.length];
        Hashtable<Double,int[]> pt = new Hashtable();
        for (int i = 0; i <points.length; i++) {
            int [] in = points[i];
            for (int j = 0; j < in.length - 1; j++) {
                Integer x = in[j];
                Integer y = in[j + 1];

                double powerX=Math.pow(x, 2);
                double powerY = Math.pow(y, 2);
                double combination= (Double)(Math.sqrt(powerX + powerY));
                pt.put(combination, points[i]);
                combinationArr[i] = combination;
            }

        }

        Arrays.sort(combinationArr);
        int [][] kpoints = new int[K][K];
        for (int n = 0; n < K; n++) {
            kpoints[n] = pt.get(combinationArr[n]);
        }
       return kpoints;
}
}    

Ответ 7

Решение С# с использованием LINQ

public int[][] KClosest(int[][] points, int K) {

    var orderedPoints = points.OrderBy(point => point[0]*point[0] + point[1]*point[1]);
    return orderedPoints.Take(K).ToArray();
}

Ответ 8

Что происходит с подходом ниже?

1) Вычислите расстояние от данной точки до других точек.

2) Сохраните расстояние и индекс этой точки до TreeMap<Double,Integer> map

3) Выберите верхние элементы K из карты. Это значение даст индекс элемента Point из массива точек.

Карта сортируется в соответствии с естественным порядком ее ключей или компаратором, предоставленным при создании карты,