8.1 KiB
title, id, localeTitle, challengeType
title | id | localeTitle | challengeType |
---|---|---|---|
Closest-pair problem | 5951a53863c8a34f02bf1bdc | 5951a53863c8a34f02bf1bdc | 5 |
Description
Proporcione una función para encontrar los dos puntos más cercanos entre un conjunto de puntos dados en dos dimensiones, es decir, para resolver el problema del par de puntos más cercano en el caso plano.
La solución directa es un algoritmo O (n 2 ) (que podemos llamar algoritmo de fuerza bruta); El pseudocódigo (utilizando índices) podría ser simplemente:
bruteForceClosestPair de P (1), P (2), ... P (N) si N <2 entonces retorno ∞ otro minDistance ← | P (1) - P (2) | minPuntos ← {P (1), P (2)} foreach i ∈ [1, N-1] foreach j ∈ [i + 1, N] si | P (i) - P (j) | <minDistance luego minDistance ← | P (i) - P (j) | minPuntos ← {P (i), P (j)} endif endfor endfor return minDistance, minPoints endif
Un mejor algoritmo se basa en el enfoque recursivo de divide y vencerás, como se explica también en el problema del par de puntos más cercanos de Wikipedia , que es O (n log n); Un pseudocódigo podría ser:
par más cercano de (xP, yP) donde xP es P (1) .. P (N) ordenada por la coordenada x, y yP es P (1) .. P (N) ordenada por la coordenada y (orden ascendente) si N ≤ 3 entonces devuelve los puntos más cercanos de xP utilizando el algoritmo de fuerza bruta más xL ← puntos de xP de 1 a ⌈N / 2⌉ xR ← puntos de xP de ⌈N / 2⌉ + 1 a N xm ← xP (⌈N / 2⌉) x yL ← {p ∈ yP: p x ≤ xm} yR ← {p ∈ yP: p x > xm} (dL, pairL) ← closestPar de (xL, yL) (dR, pairR) ← par más cercano de (xR, yR) (dmin, pairMin) ← (dR, pairR) si dL <dR luego (dmin, pairMin) ← (dL, pairL) endif yS ← { p ∈ yP: | xm - p x | <dmin} nS ← número de puntos en yS (la par más cercana, más cercana) ← (dmin, pairMin) para i de 1 a nS - 1 k ← i + 1 mientras k ≤ nS e yS (k) y - yS (i) y <dmin si | yS (k) - yS (i) | <más cercano entonces (más cercano, más cercano) ← (| yS (k) - yS (i) |, {yS (k), yS (i)}) endif k ← k + 1 endwhile endfor return más cercano más cercano par endifReferencias y otras lecturas: Par de puntos más cercanos problema Par más cercano (McGill) Par más cercano (UCSB) Par más cercano (WUStL) Par más cercano (IUPUI)
Para la entrada, espere que el argumento sea una matriz de objetos (puntos) con los miembros x
e y
establecidos en números. Para la salida, devuelva un objeto que contenga los pares clave: valor para la distance
y el pair
(es decir, el par de dos puntos más cercanos).
Instructions
Tests
tests:
- text: <code>getClosestPair</code> es una función.
testString: 'assert(typeof getClosestPair === "function", "<code>getClosestPair</code> is a function.");'
- text: La distancia debe ser la siguiente.
testString: 'assert.equal(getClosestPair(points1).distance, answer1.distance, "Distance should be the following.");'
- text: Los puntos deben ser los siguientes.
testString: 'assert.deepEqual(JSON.parse(JSON.stringify(getClosestPair(points1))).pair, answer1.pair, "Points should be the following.");'
- text: La distancia debe ser la siguiente.
testString: 'assert.equal(getClosestPair(points2).distance, answer2.distance, "Distance should be the following.");'
- text: Los puntos deben ser los siguientes.
testString: 'assert.deepEqual(JSON.parse(JSON.stringify(getClosestPair(points2))).pair, answer2.pair, "Points should be the following.");'
Challenge Seed
const Point = function (x, y) {
this.x = x;
this.y = y;
};
Point.prototype.getX = function () {
return this.x;
};
Point.prototype.getY = function () {
return this.y;
};
function getClosestPair (pointsArr) {
// Good luck!
return true;
}
After Test
console.info('after the test');
Solution
const Point = function (x, y) {
this.x = x;
this.y = y;
};
Point.prototype.getX = function () {
return this.x;
};
Point.prototype.getY = function () {
return this.y;
};
const mergeSort = function mergeSort(points, comp) {
if(points.length < 2) return points;
var n = points.length,
i = 0,
j = 0,
leftN = Math.floor(n / 2),
rightN = leftN;
var leftPart = mergeSort( points.slice(0, leftN), comp),
rightPart = mergeSort( points.slice(rightN), comp );
var sortedPart = [];
while((i < leftPart.length) && (j < rightPart.length)) {
if(comp(leftPart[i], rightPart[j]) < 0) {
sortedPart.push(leftPart[i]);
i += 1;
}
else {
sortedPart.push(rightPart[j]);
j += 1;
}
}
while(i < leftPart.length) {
sortedPart.push(leftPart[i]);
i += 1;
}
while(j < rightPart.length) {
sortedPart.push(rightPart[j]);
j += 1;
}
return sortedPart;
};
const closestPair = function _closestPair(Px, Py) {
if(Px.length < 2) return { distance: Infinity, pair: [ new Point(0, 0), new Point(0, 0) ] };
if(Px.length < 3) {
//find euclid distance
var d = Math.sqrt( Math.pow(Math.abs(Px[1].x - Px[0].x), 2) + Math.pow(Math.abs(Px[1].y - Px[0].y), 2) );
return {
distance: d,
pair: [ Px[0], Px[1] ]
};
}
var n = Px.length,
leftN = Math.floor(n / 2),
rightN = leftN;
var Xl = Px.slice(0, leftN),
Xr = Px.slice(rightN),
Xm = Xl[leftN - 1],
Yl = [],
Yr = [];
//separate Py
for(var i = 0; i < Py.length; i += 1) {
if(Py[i].x <= Xm.x)
Yl.push(Py[i]);
else
Yr.push(Py[i]);
}
var dLeft = _closestPair(Xl, Yl),
dRight = _closestPair(Xr, Yr);
var minDelta = dLeft.distance,
closestPair = dLeft.pair;
if(dLeft.distance > dRight.distance) {
minDelta = dRight.distance;
closestPair = dRight.pair;
}
//filter points around Xm within delta (minDelta)
var closeY = [];
for(i = 0; i < Py.length; i += 1) {
if(Math.abs(Py[i].x - Xm.x) < minDelta) closeY.push(Py[i]);
}
//find min within delta. 8 steps max
for(i = 0; i < closeY.length; i += 1) {
for(var j = i + 1; j < Math.min( (i + 8), closeY.length ); j += 1) {
var d = Math.sqrt( Math.pow(Math.abs(closeY[j].x - closeY[i].x), 2) + Math.pow(Math.abs(closeY[j].y - closeY[i].y), 2) );
if(d < minDelta) {
minDelta = d;
closestPair = [ closeY[i], closeY[j] ]
}
}
}
return {
distance: minDelta,
pair: closestPair
};
};
function getClosestPair (points) {
const sortX = function (a, b) { return (a.x < b.x) ? -1 : ((a.x > b.x) ? 1 : 0); }
const sortY = function (a, b) { return (a.y < b.y) ? -1 : ((a.y > b.y) ? 1 : 0); }
const Px = mergeSort(points, sortX);
const Py = mergeSort(points, sortY);
return closestPair(Px, Py);
}