Skip to content

feat: add ts solution to lc problem: No.0973 #3185

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
326 changes: 311 additions & 15 deletions solution/0900-0999/0973.K Closest Points to Origin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ tags:

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

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

<!-- tabs:start -->

Expand All @@ -80,7 +80,7 @@ tags:
```python
class Solution:
def kClosest(self, points: List[List[int]], k: int) -> List[List[int]]:
points.sort(key=lambda p: p[0] * p[0] + p[1] * p[1])
points.sort(key=lambda p: hypot(p[0], p[1]))
return points[:k]
```

Expand All @@ -89,11 +89,8 @@ class Solution:
```java
class Solution {
public int[][] kClosest(int[][] points, int k) {
Arrays.sort(points, (a, b) -> {
int d1 = a[0] * a[0] + a[1] * a[1];
int d2 = b[0] * b[0] + b[1] * b[1];
return d1 - d2;
});
Arrays.sort(
points, (p1, p2) -> Math.hypot(p1[0], p1[1]) - Math.hypot(p2[0], p2[1]) > 0 ? 1 : -1);
return Arrays.copyOfRange(points, 0, k);
}
}
Expand All @@ -105,8 +102,8 @@ class Solution {
class Solution {
public:
vector<vector<int>> kClosest(vector<vector<int>>& points, int k) {
sort(points.begin(), points.end(), [](const vector<int>& a, const vector<int>& b) {
return a[0] * a[0] + a[1] * a[1] < b[0] * b[0] + b[1] * b[1];
sort(points.begin(), points.end(), [](const vector<int>& p1, const vector<int>& p2) {
return hypot(p1[0], p1[1]) < hypot(p2[0], p2[1]);
});
return vector<vector<int>>(points.begin(), points.begin() + k);
}
Expand All @@ -118,8 +115,7 @@ public:
```go
func kClosest(points [][]int, k int) [][]int {
sort.Slice(points, func(i, j int) bool {
a, b := points[i], points[j]
return a[0]*a[0]+a[1]*a[1] < b[0]*b[0]+b[1]*b[1]
return math.Hypot(float64(points[i][0]), float64(points[i][1])) < math.Hypot(float64(points[j][0]), float64(points[j][1]))
})
return points[:k]
}
Expand All @@ -129,7 +125,8 @@ func kClosest(points [][]int, k int) [][]int {

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

Expand All @@ -138,10 +135,309 @@ function kClosest(points: number[][], k: number): number[][] {
```rust
impl Solution {
pub fn k_closest(mut points: Vec<Vec<i32>>, k: i32) -> Vec<Vec<i32>> {
points
.sort_unstable_by(|a, b| (a[0].pow(2) + a[1].pow(2)).cmp(&(b[0].pow(2) + b[1].pow(2))));
points[0..k as usize].to_vec()
points.sort_by(|a, b| {
let dist_a = f64::hypot(a[0] as f64, a[1] as f64);
let dist_b = f64::hypot(b[0] as f64, b[1] as f64);
dist_a.partial_cmp(&dist_b).unwrap()
});
points.into_iter().take(k as usize).collect()
}
}
```

<!-- tabs:end -->

<!-- solution:end -->

<!-- solution:start -->

### 方法二:优先队列(大根堆)

我们可以使用一个优先队列(大根堆)来维护距离原点最近的 $k$ 个点。

时间复杂度 $O(n \times \log k)$,空间复杂度 $O(k)$。其中 $n$ 为数组 $\text{points}$ 的长度。

<!-- tabs:start -->

#### Python3

```python
class Solution:
def kClosest(self, points: List[List[int]], k: int) -> List[List[int]]:
max_q = []
for i, (x, y) in enumerate(points):
dist = math.hypot(x, y)
heappush(max_q, (-dist, i))
if len(max_q) > k:
heappop(max_q)
return [points[i] for _, i in max_q]
```

#### Java

```java
class Solution {
public int[][] kClosest(int[][] points, int k) {
PriorityQueue<int[]> maxQ = new PriorityQueue<>((a, b) -> b[0] - a[0]);
for (int i = 0; i < points.length; ++i) {
int x = points[i][0], y = points[i][1];
maxQ.offer(new int[] {x * x + y * y, i});
if (maxQ.size() > k) {
maxQ.poll();
}
}
int[][] ans = new int[k][2];
for (int i = 0; i < k; ++i) {
ans[i] = points[maxQ.poll()[1]];
}
return ans;
}
}
```

#### C++

```cpp
class Solution {
public:
vector<vector<int>> kClosest(vector<vector<int>>& points, int k) {
priority_queue<pair<double, int>> pq;
for (int i = 0, n = points.size(); i < n; ++i) {
double dist = hypot(points[i][0], points[i][1]);
pq.push({dist, i});
if (pq.size() > k) {
pq.pop();
}
}
vector<vector<int>> ans;
while (!pq.empty()) {
ans.push_back(points[pq.top().second]);
pq.pop();
}
return ans;
}
};
```

#### Go

```go
func kClosest(points [][]int, k int) [][]int {
maxQ := hp{}
for i, p := range points {
dist := math.Hypot(float64(p[0]), float64(p[1]))
heap.Push(&maxQ, pair{dist, i})
if len(maxQ) > k {
heap.Pop(&maxQ)
}
}
ans := make([][]int, k)
for i, p := range maxQ {
ans[i] = points[p.i]
}
return ans
}

type pair struct {
dist float64
i int
}

type hp []pair

func (h hp) Len() int { return len(h) }
func (h hp) Less(i, j int) bool {
a, b := h[i], h[j]
return a.dist > b.dist
}
func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(v any) { *h = append(*h, v.(pair)) }
func (h *hp) Pop() any { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v }
```

#### TypeScript

```ts
function kClosest(points: number[][], k: number): number[][] {
const maxQ = new MaxPriorityQueue();
for (const [x, y] of points) {
const dist = x * x + y * y;
maxQ.enqueue([x, y], dist);
if (maxQ.size() > k) {
maxQ.dequeue();
}
}
return maxQ.toArray().map(item => item.element);
}
```

<!-- tabs:end -->

<!-- solution:end -->

<!-- solution:start -->

### 方法三:二分查找

我们注意到,随着距离的增大,点的数量是递增的。这存在一个临界值,使得在这个值之前的点的数量小于等于 $k$,而在这个值之后的点的数量大于 $k$。

因此,我们可以使用二分查找,枚举距离。每一次二分查找,我们统计出距离小于等于当前距离的点的数量,如果数量大于等于 $k$,则说明临界值在左侧,我们令右边界等于当前距离;否则,临界值在右侧,我们令左边界等于当前距禽加一。

二分查找结束后,我们只需要返回距离小于等于左边界的点即可。

时间复杂度 $O(n \times \log M)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $\text{points}$ 的长度,而 $M$ 为距离的最大值。

<!-- tabs:start -->

#### Python3

```python
class Solution:
def kClosest(self, points: List[List[int]], k: int) -> List[List[int]]:
dist = [x * x + y * y for x, y in points]
l, r = 0, max(dist)
while l < r:
mid = (l + r) >> 1
cnt = sum(d <= mid for d in dist)
if cnt >= k:
r = mid
else:
l = mid + 1
return [points[i] for i, d in enumerate(dist) if d <= l]
```

#### Java

```java
class Solution {
public int[][] kClosest(int[][] points, int k) {
int n = points.length;
int[] dist = new int[n];
int r = 0;
for (int i = 0; i < n; ++i) {
int x = points[i][0], y = points[i][1];
dist[i] = x * x + y * y;
r = Math.max(r, dist[i]);
}
int l = 0;
while (l < r) {
int mid = (l + r) >> 1;
int cnt = 0;
for (int d : dist) {
if (d <= mid) {
++cnt;
}
}
if (cnt >= k) {
r = mid;
} else {
l = mid + 1;
}
}
int[][] ans = new int[k][0];
for (int i = 0, j = 0; i < n; ++i) {
if (dist[i] <= l) {
ans[j++] = points[i];
}
}
return ans;
}
}
```

#### C++

```cpp
class Solution {
public:
vector<vector<int>> kClosest(vector<vector<int>>& points, int k) {
int n = points.size();
int dist[n];
int r = 0;
for (int i = 0; i < n; ++i) {
int x = points[i][0], y = points[i][1];
dist[i] = x * x + y * y;
r = max(r, dist[i]);
}
int l = 0;
while (l < r) {
int mid = (l + r) >> 1;
int cnt = 0;
for (int d : dist) {
cnt += d <= mid;
}
if (cnt >= k) {
r = mid;
} else {
l = mid + 1;
}
}
vector<vector<int>> ans;
for (int i = 0; i < n; ++i) {
if (dist[i] <= l) {
ans.emplace_back(points[i]);
}
}
return ans;
}
};
```

#### Go

```go
func kClosest(points [][]int, k int) (ans [][]int) {
n := len(points)
dist := make([]int, n)
l, r := 0, 0
for i, p := range points {
dist[i] = p[0]*p[0] + p[1]*p[1]
r = max(r, dist[i])
}
for l < r {
mid := (l + r) >> 1
cnt := 0
for _, d := range dist {
if d <= mid {
cnt++
}
}
if cnt >= k {
r = mid
} else {
l = mid + 1
}
}
for i, p := range points {
if dist[i] <= l {
ans = append(ans, p)
}
}
return
}
```

#### TypeScript

```ts
function kClosest(points: number[][], k: number): number[][] {
const dist = points.map(([x, y]) => x * x + y * y);
let [l, r] = [0, Math.max(...dist)];
while (l < r) {
const mid = (l + r) >> 1;
let cnt = 0;
for (const d of dist) {
if (d <= mid) {
++cnt;
}
}
if (cnt >= k) {
r = mid;
} else {
l = mid + 1;
}
}
return points.filter((_, i) => dist[i] <= l);
}
```

Expand Down
Loading
Loading