class Solution:
    def kClosest(self, points: List[List[int]], k: int) -> List[List[int]]:
        """
        main idea: keep a max heap size of k, push each point into it with distance to origin and its coordinate  
        tc O(NlgK) sc O(K)
        """
        pq = []
        for x,y in points:
            heapq.heappush(pq,(-x*x-y*y,x,y))
            if len(pq)> k:
                heapq.heappop(pq)
        return [[x,y] for _,x,y in pq]

Quick Selection

class Solution:
    def kClosest(self, points: List[List[int]], k: int) -> List[List[int]]:
        """tc O(N) sc O(1)
        """
        self.sort(points,k,0,len(points)-1)
        return points[:k]
    
    def sort(self,A,k,l,r):
        idx = self.partition(A,l,r)
        if idx == k-1:
            return 
        elif idx < k :
            self.sort(A,k,idx+1,r)
        else:
            self.sort(A,k,l,idx-1)
        
        
    def partition(self,A,l,r)->int:
        pivot_idx = random.randint(l,r)
        A[r],A[pivot_idx] =  A[pivot_idx], A[r]
        pivot = A[r]
        for i in range(l,r):
            if A[i][0]*A[i][0] + A[i][1]*A[i][1] < pivot[0]*pivot[0]+pivot[1]*pivot[1]:
                A[i], A[l] = A[l], A[i]
                l += 1 
        A[l], A[r] = A[r], A[l]
        return l