Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 91e3052

Browse files
rain84yanglbme
andauthored
feat: add solutions to lc problem: No.0973 (doocs#3185)
Co-authored-by: Libin YANG <contact@yanglibin.info>
1 parent 26880b8 commit 91e3052

File tree

18 files changed

+857
-47
lines changed

18 files changed

+857
-47
lines changed

‎solution/0900-0999/0973.K Closest Points to Origin/README.md‎

Lines changed: 311 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ tags:
7171

7272
我们将所有点按照与原点的距离从小到大排序,然后取前 $k$ 个点即可。
7373

74-
时间复杂度 $O(n \times \log n),ドル空间复杂度 $O(\log n)$。其中 $n$ 为数组 `points` 的长度。
74+
时间复杂度 $O(n \times \log n),ドル空间复杂度 $O(\log n)$。其中 $n$ 为数组 $\text{points}$ 的长度。
7575

7676
<!-- tabs:start -->
7777

@@ -80,7 +80,7 @@ tags:
8080
```python
8181
class Solution:
8282
def kClosest(self, points: List[List[int]], k: int) -> List[List[int]]:
83-
points.sort(key=lambda p: p[0]* p[0] + p[1] * p[1])
83+
points.sort(key=lambda p: hypot(p[0], p[1]))
8484
return points[:k]
8585
```
8686

@@ -89,11 +89,8 @@ class Solution:
8989
```java
9090
class Solution {
9191
public int[][] kClosest(int[][] points, int k) {
92-
Arrays.sort(points, (a, b) -> {
93-
int d1 = a[0] * a[0] + a[1] * a[1];
94-
int d2 = b[0] * b[0] + b[1] * b[1];
95-
return d1 - d2;
96-
});
92+
Arrays.sort(
93+
points, (p1, p2) -> Math.hypot(p1[0], p1[1]) - Math.hypot(p2[0], p2[1]) > 0 ? 1 : -1);
9794
return Arrays.copyOfRange(points, 0, k);
9895
}
9996
}
@@ -105,8 +102,8 @@ class Solution {
105102
class Solution {
106103
public:
107104
vector<vector<int>> kClosest(vector<vector<int>>& points, int k) {
108-
sort(points.begin(), points.end(), [](const vector<int>& a, const vector<int>& b) {
109-
return a[0] * a[0] + a[1] * a[1] < b[0] * b[0] + b[1] * b[1];
105+
sort(points.begin(), points.end(), [](const vector<int>& p1, const vector<int>& p2) {
106+
return hypot(p1[0], p1[1]) < hypot(p2[0], p2[1]);
110107
});
111108
return vector<vector<int>>(points.begin(), points.begin() + k);
112109
}
@@ -118,8 +115,7 @@ public:
118115
```go
119116
func kClosest(points [][]int, k int) [][]int {
120117
sort.Slice(points, func(i, j int) bool {
121-
a, b := points[i], points[j]
122-
return a[0]*a[0]+a[1]*a[1] < b[0]*b[0]+b[1]*b[1]
118+
return math.Hypot(float64(points[i][0]), float64(points[i][1])) < math.Hypot(float64(points[j][0]), float64(points[j][1]))
123119
})
124120
return points[:k]
125121
}
@@ -129,7 +125,8 @@ func kClosest(points [][]int, k int) [][]int {
129125

130126
```ts
131127
function kClosest(points: number[][], k: number): number[][] {
132-
return points.sort((a, b) => a[0] ** 2 + a[1] ** 2 - (b[0] ** 2 + b[1] ** 2)).slice(0, k);
128+
points.sort((a, b) => Math.hypot(a[0], a[1]) - Math.hypot(b[0], b[1]));
129+
return points.slice(0, k);
133130
}
134131
```
135132

@@ -138,10 +135,309 @@ function kClosest(points: number[][], k: number): number[][] {
138135
```rust
139136
impl Solution {
140137
pub fn k_closest(mut points: Vec<Vec<i32>>, k: i32) -> Vec<Vec<i32>> {
141-
points
142-
.sort_unstable_by(|a, b| (a[0].pow(2) + a[1].pow(2)).cmp(&(b[0].pow(2) + b[1].pow(2))));
143-
points[0..k as usize].to_vec()
138+
points.sort_by(|a, b| {
139+
let dist_a = f64::hypot(a[0] as f64, a[1] as f64);
140+
let dist_b = f64::hypot(b[0] as f64, b[1] as f64);
141+
dist_a.partial_cmp(&dist_b).unwrap()
142+
});
143+
points.into_iter().take(k as usize).collect()
144+
}
145+
}
146+
```
147+
148+
<!-- tabs:end -->
149+
150+
<!-- solution:end -->
151+
152+
<!-- solution:start -->
153+
154+
### 方法二:优先队列(大根堆)
155+
156+
我们可以使用一个优先队列(大根堆)来维护距离原点最近的 $k$ 个点。
157+
158+
时间复杂度 $O(n \times \log k),ドル空间复杂度 $O(k)$。其中 $n$ 为数组 $\text{points}$ 的长度。
159+
160+
<!-- tabs:start -->
161+
162+
#### Python3
163+
164+
```python
165+
class Solution:
166+
def kClosest(self, points: List[List[int]], k: int) -> List[List[int]]:
167+
max_q = []
168+
for i, (x, y) in enumerate(points):
169+
dist = math.hypot(x, y)
170+
heappush(max_q, (-dist, i))
171+
if len(max_q) > k:
172+
heappop(max_q)
173+
return [points[i] for _, i in max_q]
174+
```
175+
176+
#### Java
177+
178+
```java
179+
class Solution {
180+
public int[][] kClosest(int[][] points, int k) {
181+
PriorityQueue<int[]> maxQ = new PriorityQueue<>((a, b) -> b[0] - a[0]);
182+
for (int i = 0; i < points.length; ++i) {
183+
int x = points[i][0], y = points[i][1];
184+
maxQ.offer(new int[] {x * x + y * y, i});
185+
if (maxQ.size() > k) {
186+
maxQ.poll();
187+
}
188+
}
189+
int[][] ans = new int[k][2];
190+
for (int i = 0; i < k; ++i) {
191+
ans[i] = points[maxQ.poll()[1]];
192+
}
193+
return ans;
194+
}
195+
}
196+
```
197+
198+
#### C++
199+
200+
```cpp
201+
class Solution {
202+
public:
203+
vector<vector<int>> kClosest(vector<vector<int>>& points, int k) {
204+
priority_queue<pair<double, int>> pq;
205+
for (int i = 0, n = points.size(); i < n; ++i) {
206+
double dist = hypot(points[i][0], points[i][1]);
207+
pq.push({dist, i});
208+
if (pq.size() > k) {
209+
pq.pop();
210+
}
211+
}
212+
vector<vector<int>> ans;
213+
while (!pq.empty()) {
214+
ans.push_back(points[pq.top().second]);
215+
pq.pop();
216+
}
217+
return ans;
218+
}
219+
};
220+
```
221+
222+
#### Go
223+
224+
```go
225+
func kClosest(points [][]int, k int) [][]int {
226+
maxQ := hp{}
227+
for i, p := range points {
228+
dist := math.Hypot(float64(p[0]), float64(p[1]))
229+
heap.Push(&maxQ, pair{dist, i})
230+
if len(maxQ) > k {
231+
heap.Pop(&maxQ)
232+
}
233+
}
234+
ans := make([][]int, k)
235+
for i, p := range maxQ {
236+
ans[i] = points[p.i]
237+
}
238+
return ans
239+
}
240+
241+
type pair struct {
242+
dist float64
243+
i int
244+
}
245+
246+
type hp []pair
247+
248+
func (h hp) Len() int { return len(h) }
249+
func (h hp) Less(i, j int) bool {
250+
a, b := h[i], h[j]
251+
return a.dist > b.dist
252+
}
253+
func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
254+
func (h *hp) Push(v any) { *h = append(*h, v.(pair)) }
255+
func (h *hp) Pop() any { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v }
256+
```
257+
258+
#### TypeScript
259+
260+
```ts
261+
function kClosest(points: number[][], k: number): number[][] {
262+
const maxQ = new MaxPriorityQueue();
263+
for (const [x, y] of points) {
264+
const dist = x * x + y * y;
265+
maxQ.enqueue([x, y], dist);
266+
if (maxQ.size() > k) {
267+
maxQ.dequeue();
268+
}
269+
}
270+
return maxQ.toArray().map(item => item.element);
271+
}
272+
```
273+
274+
<!-- tabs:end -->
275+
276+
<!-- solution:end -->
277+
278+
<!-- solution:start -->
279+
280+
### 方法三:二分查找
281+
282+
我们注意到,随着距离的增大,点的数量是递增的。这存在一个临界值,使得在这个值之前的点的数量小于等于 $k,ドル而在这个值之后的点的数量大于 $k$。
283+
284+
因此,我们可以使用二分查找,枚举距离。每一次二分查找,我们统计出距离小于等于当前距离的点的数量,如果数量大于等于 $k,ドル则说明临界值在左侧,我们令右边界等于当前距离;否则,临界值在右侧,我们令左边界等于当前距禽加一。
285+
286+
二分查找结束后,我们只需要返回距离小于等于左边界的点即可。
287+
288+
时间复杂度 $O(n \times \log M),ドル空间复杂度 $O(n)$。其中 $n$ 为数组 $\text{points}$ 的长度,而 $M$ 为距离的最大值。
289+
290+
<!-- tabs:start -->
291+
292+
#### Python3
293+
294+
```python
295+
class Solution:
296+
def kClosest(self, points: List[List[int]], k: int) -> List[List[int]]:
297+
dist = [x * x + y * y for x, y in points]
298+
l, r = 0, max(dist)
299+
while l < r:
300+
mid = (l + r) >> 1
301+
cnt = sum(d <= mid for d in dist)
302+
if cnt >= k:
303+
r = mid
304+
else:
305+
l = mid + 1
306+
return [points[i] for i, d in enumerate(dist) if d <= l]
307+
```
308+
309+
#### Java
310+
311+
```java
312+
class Solution {
313+
public int[][] kClosest(int[][] points, int k) {
314+
int n = points.length;
315+
int[] dist = new int[n];
316+
int r = 0;
317+
for (int i = 0; i < n; ++i) {
318+
int x = points[i][0], y = points[i][1];
319+
dist[i] = x * x + y * y;
320+
r = Math.max(r, dist[i]);
321+
}
322+
int l = 0;
323+
while (l < r) {
324+
int mid = (l + r) >> 1;
325+
int cnt = 0;
326+
for (int d : dist) {
327+
if (d <= mid) {
328+
++cnt;
329+
}
330+
}
331+
if (cnt >= k) {
332+
r = mid;
333+
} else {
334+
l = mid + 1;
335+
}
336+
}
337+
int[][] ans = new int[k][0];
338+
for (int i = 0, j = 0; i < n; ++i) {
339+
if (dist[i] <= l) {
340+
ans[j++] = points[i];
341+
}
342+
}
343+
return ans;
344+
}
345+
}
346+
```
347+
348+
#### C++
349+
350+
```cpp
351+
class Solution {
352+
public:
353+
vector<vector<int>> kClosest(vector<vector<int>>& points, int k) {
354+
int n = points.size();
355+
int dist[n];
356+
int r = 0;
357+
for (int i = 0; i < n; ++i) {
358+
int x = points[i][0], y = points[i][1];
359+
dist[i] = x * x + y * y;
360+
r = max(r, dist[i]);
361+
}
362+
int l = 0;
363+
while (l < r) {
364+
int mid = (l + r) >> 1;
365+
int cnt = 0;
366+
for (int d : dist) {
367+
cnt += d <= mid;
368+
}
369+
if (cnt >= k) {
370+
r = mid;
371+
} else {
372+
l = mid + 1;
373+
}
374+
}
375+
vector<vector<int>> ans;
376+
for (int i = 0; i < n; ++i) {
377+
if (dist[i] <= l) {
378+
ans.emplace_back(points[i]);
379+
}
380+
}
381+
return ans;
382+
}
383+
};
384+
```
385+
386+
#### Go
387+
388+
```go
389+
func kClosest(points [][]int, k int) (ans [][]int) {
390+
n := len(points)
391+
dist := make([]int, n)
392+
l, r := 0, 0
393+
for i, p := range points {
394+
dist[i] = p[0]*p[0] + p[1]*p[1]
395+
r = max(r, dist[i])
396+
}
397+
for l < r {
398+
mid := (l + r) >> 1
399+
cnt := 0
400+
for _, d := range dist {
401+
if d <= mid {
402+
cnt++
403+
}
404+
}
405+
if cnt >= k {
406+
r = mid
407+
} else {
408+
l = mid + 1
409+
}
410+
}
411+
for i, p := range points {
412+
if dist[i] <= l {
413+
ans = append(ans, p)
414+
}
415+
}
416+
return
417+
}
418+
```
419+
420+
#### TypeScript
421+
422+
```ts
423+
function kClosest(points: number[][], k: number): number[][] {
424+
const dist = points.map(([x, y]) => x * x + y * y);
425+
let [l, r] = [0, Math.max(...dist)];
426+
while (l < r) {
427+
const mid = (l + r) >> 1;
428+
let cnt = 0;
429+
for (const d of dist) {
430+
if (d <= mid) {
431+
++cnt;
432+
}
433+
}
434+
if (cnt >= k) {
435+
r = mid;
436+
} else {
437+
l = mid + 1;
438+
}
144439
}
440+
return points.filter((_, i) => dist[i] <= l);
145441
}
146442
```
147443

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /