我们在3d空间中给出n个点,我们需要找到严格小于3d空间中至少一个点的所有点的计数 即。
x1<x2 and y1<y2 and z1<z2
所以(x1,y1,z1)就是这样一个点。
For example,Given points
1 4 2
4 3 2
2 5 3
(1,4,2)<(2,5,3)
So the answer for the above case should be the count of such points i.e. 1.
我知道这可以通过O(n ^ 2)算法解决,但我需要更快的东西,我尝试通过一个维度进行排序,然后只搜索密钥的大部分,但它仍然是o(n ^ 2 ) 最糟糕的情况。
这样做的有效方法是什么?
答案 0 :(得分:1)
有一种优化搜索的方法可能比O(n^2)
更快 - 我欢迎反采样输入。
保留三个点的索引列表,分别按x,y和z排序。制作第四个列表,将每个点与它在每个列表中的位置相关联(indexes
在下面的代码中;例如,indexes[0] = [5,124,789]
表示第一个点在x排序列表中是第5个,在第124个位置是y排序列表,z排序列表中的第789位。
现在迭代点 - 选择点最高的列表并根据列表中较高的索引点测试点,如果该点严格小于其中一个,则提前退出。如果所有三个列表上的点都很低,则找到严格更高点的可能性更大。否则,其中一个列表中的较高位置意味着较少的迭代。
JavaScript代码:
function strictlyLessThan(p1,p2){
return p1[0] < p2[0] && p1[1] < p2[1] && p1[2] < p2[2];
}
// iterations
var it = 0;
function f(ps){
var res = 0,
indexes = new Array(ps.length);
// sort by x
var sortedX =
ps.map(function(x,i){ return i; })
.sort(function(a,b){ return ps[a][0] - ps[b][0]; });
// record index of point in x-sorted list
for (var i=0; i<sortedX.length; i++){
indexes[sortedX[i]] = [i,null,null];
}
// sort by y
var sortedY =
ps.map(function(x,i){ return i; })
.sort(function(a,b){ return ps[a][1] - ps[b][1]; });
// record index of point in y-sorted list
for (var i=0; i<sortedY.length; i++){
indexes[sortedY[i]][1] = i;
}
// sort by z
var sortedZ =
ps.map(function(x,i){ return i; })
.sort(function(a,b){ return ps[a][2] - ps[b][2]; });
// record index of point in z-sorted list
for (var i=0; i<sortedZ.length; i++){
indexes[sortedZ[i]][2] = i;
}
// check for possible greater points only in the list
// where the point is highest
for (var i=0; i<ps.length; i++){
var listToCheck,
startIndex;
if (indexes[i][0] > indexes[i][1]){
if (indexes[i][0] > indexes[i][2]){
listToCheck = sortedX;
startIndex = indexes[i][0];
} else {
listToCheck = sortedZ;
startIndex = indexes[i][2];
}
} else {
if (indexes[i][1] > indexes[i][2]){
listToCheck = sortedY;
startIndex = indexes[i][1];
} else {
listToCheck = sortedZ;
startIndex = indexes[i][2];
}
}
var j = startIndex + 1;
while (listToCheck[j] !== undefined){
it++;
var point = ps[listToCheck[j]];
if (strictlyLessThan(ps[i],point)){
res++;
break;
}
j++;
}
}
return res;
}
// var input = [[5,0,0],[4,1,0],[3,2,0],[2,3,0],[1,4,0],[0,5,0],[4,0,1],[3,1,1], [2,2,1],[1,3,1],[0,4,1],[3,0,2],[2,1,2],[1,2,2],[0,3,2],[2,0,3], [1,1,3],[0,2,3],[1,0,4],[0,1,4],[0,0,5]];
var input = new Array(10000);
for (var i=0; i<input.length; i++){
input[i] = [Math.random(),Math.random(),Math.random()];
}
console.log(input.length + ' points');
console.log('result: ' + f(input));
console.log(it + ' iterations not including sorts');
答案 1 :(得分:0)
我怀疑最坏情况的复杂性可以降低到N×N以下,因为有可能创建输入,其中没有点严格小于任何其他点:
对于任何值 n ,考虑与Z,Y和Z轴在(n,0,0),(0,n,0)和(0,0, n),由等式 x + y + z = n 描述。如果输入由这样一个平面上的点组成,则没有一个点严格小于任何其他点。
最坏情况输入的示例:
(5,0,0) (4,1,0) (3,2,0) (2,3,0) (1,4,0) (0,5,0)
(4,0,1) (3,1,1) (2,2,1) (1,3,1) (0,4,1)
(3,0,2) (2,1,2) (1,2,2) (0,3,2)
(2,0,3) (1,1,3) (0,2,3)
(1,0,4) (0,1,4)
(0,0,5)
然而,平均复杂度可以降低到远小于N×N,例如,用这种方法:
由于任何两个随机点 a 和 b a&lt; b或b&lt; a的概率为25%,因此列表不会变得非常大大(除非输入是专门设计为包含很少或没有严格小于任何其他点的点)。
使用下面的代码(100个案例)进行有限测试,在立方空间中随机分布1,000,000个点,表明平均列表大小约为116(最大值为160),检查点是否严格少于比另一点大约1,333,000(最多2,150,000)。
(一些10,000,000点的测试显示平均支票数约为11,000,000,列表大小约为150.)
因此在实践中,平均复杂度接近N而不是N×N。
function xyzLessCount(input) {
var list = [input[0]]; // put first point in list
for (var i = 1; i < input.length; i++) { // check every point in input
var append = true;
for (var j = 0; j < list.length; j++) { // against every point in list
if (xyzLess(input[i], list[j])) { // new point < list point
append = false;
break; // continue with next point
}
if (xyzLess(list[j], input[i])) { // new point > list point
list[j] = input[i]; // replace list point
for (var k = list.length - 1; k > j; k--) {
if (xyzLess(list[k], list[j])) { // check rest of list
list.splice(k, 1); // remove list point
}
}
append = false;
break; // continue with next point
}
}
if (append) list.push(input[i]); // append new point to list
}
return input.length - list.length;
function xyzLess(a, b) {
return a.x < b.x && a.y < b.y && a.z < b.z;
}
}
var points = []; // random test data
for (var i = 0; i < 1000000; i++) {
points.push({x: Math.random(), y: Math.random(), z: Math.random()});
}
document.write("1000000 → " + xyzLessCount(points));