Skip to content

Commit 33193f9

Browse files
committed
feat(js): add modular solution and documentation for hard challenge 5 - Line Sweep Closest Points
1 parent b71f394 commit 33193f9

File tree

3 files changed

+265
-0
lines changed

3 files changed

+265
-0
lines changed
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
# Line Sweep Algorithm - Closest Pair of Points
2+
3+
## English
4+
5+
The line sweep algorithm is a powerful technique in computational geometry for solving proximity problems efficiently. It reduces the complexity of finding the closest pair of points from O(n^2) to O(n log n) by sweeping a line across the plane and maintaining a dynamic set of candidate points.
6+
7+
This challenge involves using the line sweep algorithm to find the closest pair of points in a set of 2D coordinates.
8+
9+
### Relevant Code Snippet
10+
11+
```javascript
12+
class ClosestPoints {
13+
constructor(points) {
14+
this.points = points.slice().sort((a, b) => a[0] - b[0]);
15+
}
16+
17+
distance(p1, p2) {
18+
return Math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2);
19+
}
20+
21+
findClosestPair() {
22+
const active = [];
23+
let bestPair = [null, null];
24+
let bestDist = Infinity;
25+
let left = 0;
26+
27+
const bisectLeft = (arr, x) => {
28+
let low = 0, high = arr.length;
29+
while (low < high) {
30+
const mid = Math.floor((low + high) / 2);
31+
if (arr[mid] < x) low = mid + 1;
32+
else high = mid;
33+
}
34+
return low;
35+
};
36+
37+
const bisectRight = (arr, x) => {
38+
let low = 0, high = arr.length;
39+
while (low < high) {
40+
const mid = Math.floor((low + high) / 2);
41+
if (arr[mid] <= x) low = mid + 1;
42+
else high = mid;
43+
}
44+
return low;
45+
};
46+
47+
for (const point of this.points) {
48+
while (active.length > 0 && point[0] - this.points[left][0] > bestDist) {
49+
const idx = bisectLeft(active, this.points[left][1]);
50+
if (idx < active.length && active[idx] === this.points[left][1]) {
51+
active.splice(idx, 1);
52+
}
53+
left++;
54+
}
55+
56+
const yLower = point[1] - bestDist;
57+
const yUpper = point[1] + bestDist;
58+
const i = bisectLeft(active, yLower);
59+
const j = bisectRight(active, yUpper);
60+
61+
for (let k = i; k < j; k++) {
62+
const candidate = [point[0], active[k]];
63+
const dist = this.distance(point, candidate);
64+
if (dist < bestDist) {
65+
bestDist = dist;
66+
bestPair = [point, candidate];
67+
}
68+
}
69+
70+
const pos = bisectLeft(active, point[1]);
71+
active.splice(pos, 0, point[1]);
72+
}
73+
74+
return { pair: bestPair, distance: bestDist };
75+
}
76+
}
77+
```
78+
79+
### History
80+
81+
The line sweep algorithm has been widely used in computational geometry for efficient proximity queries and spatial optimization problems.
82+
83+
---
84+
85+
## Español
86+
87+
Algoritmo de Barrido Lineal - Par de Puntos Más Cercanos
88+
89+
El algoritmo de barrido lineal es una técnica poderosa en geometría computacional para resolver problemas de proximidad eficientemente. Reduce la complejidad de encontrar el par de puntos más cercanos de O(n^2) a O(n log n) al barrer una línea a través del plano y mantener un conjunto dinámico de puntos candidatos.
90+
91+
Este reto consiste en usar el algoritmo de barrido lineal para encontrar el par de puntos más cercanos en un conjunto de coordenadas 2D.
92+
93+
### Fragmento de Código Relevante
94+
95+
```javascript
96+
class ClosestPoints {
97+
constructor(points) {
98+
this.points = points.slice().sort((a, b) => a[0] - b[0]);
99+
}
100+
101+
distance(p1, p2) {
102+
return Math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2);
103+
}
104+
105+
findClosestPair() {
106+
const active = [];
107+
let bestPair = [null, null];
108+
let bestDist = Infinity;
109+
let left = 0;
110+
111+
const bisectLeft = (arr, x) => {
112+
let low = 0, high = arr.length;
113+
while (low < high) {
114+
const mid = Math.floor((low + high) / 2);
115+
if (arr[mid] < x) low = mid + 1;
116+
else high = mid;
117+
}
118+
return low;
119+
};
120+
121+
const bisectRight = (arr, x) => {
122+
let low = 0, high = arr.length;
123+
while (low < high) {
124+
const mid = Math.floor((low + high) / 2);
125+
if (arr[mid] <= x) low = mid + 1;
126+
else high = mid;
127+
}
128+
return low;
129+
};
130+
131+
for (const point of this.points) {
132+
while (active.length > 0 && point[0] - this.points[left][0] > bestDist) {
133+
const idx = bisectLeft(active, this.points[left][1]);
134+
if (idx < active.length && active[idx] === this.points[left][1]) {
135+
active.splice(idx, 1);
136+
}
137+
left++;
138+
}
139+
140+
const yLower = point[1] - bestDist;
141+
const yUpper = point[1] + bestDist;
142+
const i = bisectLeft(active, yLower);
143+
const j = bisectRight(active, yUpper);
144+
145+
for (let k = i; k < j; k++) {
146+
const candidate = [point[0], active[k]];
147+
const dist = this.distance(point, candidate);
148+
if (dist < bestDist) {
149+
bestDist = dist;
150+
bestPair = [point, candidate];
151+
}
152+
}
153+
154+
const pos = bisectLeft(active, point[1]);
155+
active.splice(pos, 0, point[1]);
156+
}
157+
158+
return { pair: bestPair, distance: bestDist };
159+
}
160+
}
161+
```
162+
163+
### Historia
164+
165+
El algoritmo de barrido lineal ha sido ampliamente usado en geometría computacional para consultas de proximidad eficientes y problemas de optimización espacial.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// ClosestPoints.js - Line Sweep Algorithm to find closest pair of points in JavaScript
2+
3+
class ClosestPoints {
4+
constructor(points) {
5+
this.points = points.slice().sort((a, b) => a[0] - b[0]);
6+
}
7+
8+
distance(p1, p2) {
9+
return Math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2);
10+
}
11+
12+
findClosestPair() {
13+
const active = [];
14+
let bestPair = [null, null];
15+
let bestDist = Infinity;
16+
let left = 0;
17+
18+
const bisectLeft = (arr, x) => {
19+
let low = 0,
20+
high = arr.length;
21+
while (low < high) {
22+
const mid = Math.floor((low + high) / 2);
23+
if (arr[mid] < x) low = mid + 1;
24+
else high = mid;
25+
}
26+
return low;
27+
};
28+
29+
const bisectRight = (arr, x) => {
30+
let low = 0,
31+
high = arr.length;
32+
while (low < high) {
33+
const mid = Math.floor((low + high) / 2);
34+
if (arr[mid] <= x) low = mid + 1;
35+
else high = mid;
36+
}
37+
return low;
38+
};
39+
40+
for (const point of this.points) {
41+
while (active.length > 0 && point[0] - this.points[left][0] > bestDist) {
42+
// Remove points[left][1] from active using binary search
43+
const idx = bisectLeft(active, this.points[left][1]);
44+
if (idx < active.length && active[idx] === this.points[left][1]) {
45+
active.splice(idx, 1);
46+
}
47+
left++;
48+
}
49+
50+
const yLower = point[1] - bestDist;
51+
const yUpper = point[1] + bestDist;
52+
const i = bisectLeft(active, yLower);
53+
const j = bisectRight(active, yUpper);
54+
55+
for (let k = i; k < j; k++) {
56+
const candidate = [point[0], active[k]];
57+
const dist = this.distance(point, candidate);
58+
if (dist < bestDist) {
59+
bestDist = dist;
60+
bestPair = [point, candidate];
61+
}
62+
}
63+
64+
// Insert point[1] into active in sorted order
65+
const pos = bisectLeft(active, point[1]);
66+
active.splice(pos, 0, point[1]);
67+
}
68+
69+
return { pair: bestPair, distance: bestDist };
70+
}
71+
}
72+
73+
export default ClosestPoints;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
Challenge:
3+
Use the line sweep algorithm to find the closest pair of points in a set of 2D coordinates.
4+
5+
This solution follows DRY principles and is implemented in JavaScript.
6+
*/
7+
8+
import ClosestPoints from "./ClosestPoints.js";
9+
10+
function main() {
11+
const points = [
12+
[2, 3],
13+
[12, 30],
14+
[40, 50],
15+
[5, 1],
16+
[12, 10],
17+
[3, 4],
18+
];
19+
20+
const closestPoints = new ClosestPoints(points);
21+
const result = closestPoints.findClosestPair();
22+
23+
console.log("Closest pair of points:", result.pair);
24+
console.log("Distance between closest points:", result.distance);
25+
}
26+
27+
main();

0 commit comments

Comments
 (0)