LC 973. K Closest Points to Origin

Sarthak Sehgal · March 15, 2020

Solution

A straightforward solution can be to sort the given array based on a custom comparator which compares Eucledian distance of two points but that would take up O(NlogN) time.
Another approach can be using a min-heap but if you think further, it would take up O(NlogN) time as well. Instead, we will use a max heap

Approach 1: Using Max Heap

We will start storing elements in a max heap. Whenever the heap has K+1 elements, we will pop an element from the heap. The popped element is the greatest element amongst the K+1 elements so it should not be in our answer (we want the K smallest elements). At the end, the heap will contain K smallest elements. Note that to compare two elements, we have to compare them by their Eucledian distance from the origin.

vector<vector<int>> kClosest(vector<vector<int>>& points, int K) {
    // by default priority queue compares vectors using the first element of the vector
    priority_queue<vector<int>> pq;

    for (int i=0; i<points.size(); i++) {
        // store the eucledian distance as first element of the array, second element -> x coordinate, third element -> y coordinate
        pq.push({points[i][0]*points[i][0] + points[i][1]*points[i][1], points[i][0], points[i][1]});

        // if the heap has K+1 elements, pop an element
        if (i>=K)
            pq.pop();
    }

    vector<vector<int>> ans;
    while (pq.size()>0) {
        vector<int> v = pq.top();
        pq.pop();
        ans.push_back({v[1], v[2]});
    }

    return ans;
}

Consider an example:

points = [[3,3],[5,-1],[-2,4]], K = 2

i=0:
pq -> {[18,3,3]}

i=1:
pq -> {[27,5,-1], [18,3,3]}

i=2:
pq -> {[20,-2,4], [18,3,3]}

Time complexity: O(NlogK)
Space complexity: O(K)

Approach 2: Using STL algorithm nth_element

nth_element rearranges the list in such a way such that the element at the nth position is the one which should be at that position if we sort the list.

vector<vector<int>> kClosest(vector<vector<int>>& points, int K) {
    nth_element(points.begin(), points.begin()+K-1, points.end(), [](vector<int> p1, vector<int> p2) {
        return p1[0]*p1[0]+p1[1]*p1[1] < p2[0]*p2[0]+p2[1]*p2[1];
    });

    return vector<vector<int>>(points.begin(), points.begin()+K);
}

Approach 3: Using STL algorithm partial_sort

partial_sort is used for sorting not the entire range, but only a sub-part of it. Here we can partial sort K elements. Note that it considers all the elements of the array while sorting (i.e., it is different from sorting only the first K elements of array).

vector<vector<int>> kClosest(vector<vector<int>>& points, int K) {
    partial_sort(points.begin(), points.begin()+K, points.end(), [](vector<int> p1, vector<int> p2) {
        return p1[0]*p1[0]+p1[1]*p1[1] < p2[0]*p2[0]+p2[1]*p2[1];
    });

    return vector<vector<int>>(points.begin(), points.begin()+K);
}

Good watch if you’re interested in learning more about nth_element and partial_sort: CppCon 2018: Fred Tingaud “A Little Order: Delving into the STL sorting algorithms”.

Twitter, Facebook