* feat(tools): add seed/solution restore script * chore(curriculum): remove empty sections' markers * chore(curriculum): add seed + solution to Chinese * chore: remove old formatter * fix: update getChallenges parse translated challenges separately, without reference to the source * chore(curriculum): add dashedName to English * chore(curriculum): add dashedName to Chinese * refactor: remove unused challenge property 'name' * fix: relax dashedName requirement * fix: stray tag Remove stray `pre` tag from challenge file. Signed-off-by: nhcarrigan <nhcarrigan@gmail.com> Co-authored-by: nhcarrigan <nhcarrigan@gmail.com>
9.4 KiB
9.4 KiB
id, title, challengeType, videoUrl, dashedName
id | title | challengeType | videoUrl | dashedName |
---|---|---|---|---|
5951a53863c8a34f02bf1bdc | 最近对的问题 | 5 | closest-pair-problem |
--description--
任务:
提供一个函数来在二维中找到一组给定点中最接近的两个点,即求解平面情况下的最近点对问题 。
直接的解决方案是O(n 2 )算法(我们可以称之为强力算法);伪代码(使用索引)可以简单地:
bruteForceClosestPair of P(1),P(2),... P(N)
如果N <2那么
返回∞
其他
minDistance←| P(1) - P(2)|
minPoints←{P(1),P(2)}
foreachi∈[1,N-1]
foreachj∈[i + 1,N]
if | P(i) - P(j)| <minDistance然后
minDistance←| P(i) - P(j)|
minPoints←{P(i),P(j)}
万一
ENDFOR
ENDFOR
return minDistance,minPoints
万一
一个更好的算法是基于递归分而治之的方法,正如维基百科最近的一对点问题所解释的那样,即O(n log n);伪代码可以是:
最近的(xP,yP) 其中xP是P(1).. P(N)按x坐标排序,和 yP是P(1).. P(N)按y坐标排序(升序) 如果N≤3那么 使用强力算法返回xP的最近点 其他 xL←xP点从1到⌈N/2⌉ xR←xP点从⌈N/2⌉+ 1到N. xm←xP(⌈N/2⌉) x 基←{P∈YP:P X≤XM} yR←{p∈yP:p x > xm} (dL,pairL)←nearestPair(xL,yL) (dR,pairR)←nearestRair(xR,yR) (dmin,pairMin)←(dR,pairR) 如果dL <dR则 (dmin,pairMin)←(dL,pairL) 万一 yS←{p∈yP:| xm - p x | <dmin} nS←yS中的点数 (最近,最近的公里)←(dmin,pairMin) 我从1到nS - 1 k←i + 1 而k≤nS和yS(k) y -yS(i) y <dmin if | yS(k) - yS(i)| <最接近的 (最近,最近的公里)←(| yS(k) - yS(i)|,{yS(k),yS(i)}) 万一 k←k + 1 ENDWHILE ENDFOR 返回最近,最近的 万一参考和进一步阅读: 最近的一对点问题 最近的一对(麦吉尔) 最近的一对(UCSB) 最近的一对(WUStL) 最近的一对(IUPUI)
对于输入,期望参数是一个对象(点)数组,其中x
和y
成员设置为数字。对于输出,返回一个包含键的对象: distance
和pair
值对(即两对最近点的对)。
--hints--
getClosestPair
是一个函数。
assert(typeof getClosestPair === 'function');
距离应如下。
assert.equal(getClosestPair(points1).distance, answer1.distance);
要点应如下。
assert.deepEqual(
JSON.parse(JSON.stringify(getClosestPair(points1))).pair,
answer1.pair
);
距离应如下。
assert.equal(getClosestPair(points2).distance, answer2.distance);
要点应如下。
assert.deepEqual(
JSON.parse(JSON.stringify(getClosestPair(points2))).pair,
answer2.pair
);
--seed--
--after-user-code--
const points1 = [
new Point(0.748501, 4.09624),
new Point(3.00302, 5.26164),
new Point(3.61878, 9.52232),
new Point(7.46911, 4.71611),
new Point(5.7819, 2.69367),
new Point(2.34709, 8.74782),
new Point(2.87169, 5.97774),
new Point(6.33101, 0.463131),
new Point(7.46489, 4.6268),
new Point(1.45428, 0.087596)
];
const points2 = [
new Point(37100, 13118),
new Point(37134, 1963),
new Point(37181, 2008),
new Point(37276, 21611),
new Point(37307, 9320)
];
const answer1 = {
distance: 0.0894096443343775,
pair: [
{
x: 7.46489,
y: 4.6268
},
{
x: 7.46911,
y: 4.71611
}
]
};
const answer2 = {
distance: 65.06919393998976,
pair: [
{
x: 37134,
y: 1963
},
{
x: 37181,
y: 2008
}
]
};
const benchmarkPoints = [
new Point(16909, 54699),
new Point(14773, 61107),
new Point(95547, 45344),
new Point(95951, 17573),
new Point(5824, 41072),
new Point(8769, 52562),
new Point(21182, 41881),
new Point(53226, 45749),
new Point(68180, 887),
new Point(29322, 44017),
new Point(46817, 64975),
new Point(10501, 483),
new Point(57094, 60703),
new Point(23318, 35472),
new Point(72452, 88070),
new Point(67775, 28659),
new Point(19450, 20518),
new Point(17314, 26927),
new Point(98088, 11164),
new Point(25050, 56835),
new Point(8364, 6892),
new Point(37868, 18382),
new Point(23723, 7701),
new Point(55767, 11569),
new Point(70721, 66707),
new Point(31863, 9837),
new Point(49358, 30795),
new Point(13041, 39745),
new Point(59635, 26523),
new Point(25859, 1292),
new Point(1551, 53890),
new Point(70316, 94479),
new Point(48549, 86338),
new Point(46413, 92747),
new Point(27186, 50426),
new Point(27591, 22655),
new Point(10905, 46153),
new Point(40408, 84202),
new Point(52821, 73520),
new Point(84865, 77388),
new Point(99819, 32527),
new Point(34404, 75657),
new Point(78457, 96615),
new Point(42140, 5564),
new Point(62175, 92342),
new Point(54958, 67112),
new Point(4092, 19709),
new Point(99415, 60298),
new Point(51090, 52158),
new Point(48953, 58567)
];
--seed-contents--
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) {
return true;
}
--solutions--
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);
}