71
71
72
72
我们将所有点按照与原点的距离从小到大排序,然后取前 $k$ 个点即可。
73
73
74
- 时间复杂度 $O(n \times \log n)$,空间复杂度 $O(\log n)$。其中 $n$ 为数组 ` points ` 的长度。
74
+ 时间复杂度 $O(n \times \log n)$,空间复杂度 $O(\log n)$。其中 $n$ 为数组 $\text{ points}$ 的长度。
75
75
76
76
<!-- tabs:start -->
77
77
80
80
``` python
81
81
class Solution :
82
82
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 ]) )
84
84
return points[:k]
85
85
```
86
86
@@ -89,11 +89,8 @@ class Solution:
89
89
``` java
90
90
class Solution {
91
91
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 );
97
94
return Arrays . copyOfRange(points, 0 , k);
98
95
}
99
96
}
@@ -105,8 +102,8 @@ class Solution {
105
102
class Solution {
106
103
public:
107
104
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 ] ) ;
110
107
});
111
108
return vector<vector<int >>(points.begin(), points.begin() + k);
112
109
}
@@ -118,8 +115,7 @@ public:
118
115
```go
119
116
func kClosest(points [][]int, k int) [][]int {
120
117
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]))
123
119
})
124
120
return points[:k]
125
121
}
@@ -129,7 +125,8 @@ func kClosest(points [][]int, k int) [][]int {
129
125
130
126
``` ts
131
127
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 );
133
130
}
134
131
```
135
132
@@ -138,10 +135,309 @@ function kClosest(points: number[][], k: number): number[][] {
138
135
``` rust
139
136
impl Solution {
140
137
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
+ }
144
439
}
440
+ return points .filter ((_ , i ) => dist [i ] <= l );
145
441
}
146
442
```
147
443
0 commit comments