The problem
Given an array of points
where points[i] = [xi, yi]
represents a point on the X-Y plane and an integer k
, return the k
closest points to the origin (0, 0)
.
The distance between two points on the X-Y plane is the Euclidean distance (i.e., √(x1 - x2)^2 + (y1 - y2)^2
).
You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in).
Examples
Input: points = [[1,3],[-2,2]], k = 1
Output: [[-2,2]]
Explanation:
The distance between (1, 3) and the origin is sqrt(10).
The distance between (-2, 2) and the origin is sqrt(8).
Since sqrt(8) < sqrt(10), (-2, 2) is closer to the origin.
We only want the closest k = 1 points from the origin, so the answer is just [[-2,2]].
Input: points = [[3,3],[5,-1],[-2,4]], k = 2
Output: [[3,3],[-2,4]]
Explanation: The answer [[-2,4],[3,3]] would also be accepted.
Constraints
- 1 <= k <= points.length <= 10^4
- -10^4 <= xi, yi <= 10^4
Explanation
From the description of the problem we learn that we have an array of points
that is represented as a pair of values and we need to return the closest points to the origin, where the origin is the center with coordinates [0, 0]
. We are also given the k
parameter that tells us the number of closest elements to the origin that we need to return.
Let’s look at our first example with input points = [[1,3],[-2,2]], k = 1
In this example we only need to return a single closest element because k = 1
.
The first thing that we need to do is figure out how far the given points
are from the origin. We can do that by using the formula (x1 - x2)^2 + (y1 - y2)^2
.
We can avoid using sqrt
because we do not need to find the distance, we only need to find which one of the points is greater.
- When we calculate how far the coordinates
[1, 3]
are we get the result(1 - 0)^2 + (3 - 0)^2 = 10
- When we calculate how far the coordinates
[-2, 2]
are we get the result(-2 - 0)^2 + (2 - 0)^2 = 8
You can see that coordinates [-2, 2]
are closer to the origin than [1, 3]
. Now we need to figure out the way to find k
closest elements.
Sorting Solution
func kClosest(_ points: [[Int]], _ k: Int) -> [[Int]] {
var points = points
points.sort { (p1, p2) in
let dist1 = p1[0] * p1[0] + p1[1] * p1[1]
let dist2 = p2[0] * p2[0] + p2[1] * p2[1]
return dist1 < dist2
}
return Array(points.prefix(k))
}
Explanation
The brute force way to find k
closest elements is to sort our input, but it’s not very efficient in terms of time complexity because it will take O(n*log(n))
time.
Time/ Space complexity
- Time complexity: O(n*log(n))
- Space complexity: O(1) or O(n) depending on the sorting algorithm
Min Heap Solution
func kClosest(_ points: [[Int]], _ k: Int) -> [[Int]] {
var minHeap: Heap<Helper> = Heap()
for point in points {
let x = point[0]
let y = point[1]
let dist = x*x + y*y
minHeap.insert(Helper(dist: dist, x: x, y: y))
}
var res: [[Int]] = []
for _ in 0 ..< k {
let helper = minHeap.removeMin()
res.append([helper.x, helper.y])
}
return res
}
struct Helper: Comparable {
static func < (lhs: Helper, rhs: Helper) -> Bool {
return lhs.dist < rhs.dist
}
let dist: Int
let x: Int
let y: Int
}
Explanation
Above we learned that sorting is not very efficient. We can optimize this problem by using a min heap data structure so our overall time complexity will be O(k*log(n))
.
- The first step we are going to do is figure out the distance. We will use it as the first element by putting the coordinates into our min heap because it will be the element that we want our min heap to be ordered by.
- The next step is we will be popping from the min heap
k
times, which will takeO(logn)
time. As a result, we will be returning coordinates[-2, 2]
because they have the smaller distance and we only need to pop once because ourk = 1
.
Time/ Space complexity
- Time complexity: O(k*log(n))
- Space complexity: O(n)