在我将实际测试作为工作申请的一部分之前,我正在尝试 Codility 的演示问题。他们的一个演示是一个问题,涉及计算磁盘阵列的磁盘交叉点的数量。
任务描述是
给定一个包含 N 个整数的数组 A,我们在 2D 平面中绘制 N 个圆盘,使得第 I 个圆盘以 (0,I) 为中心,半径为 A[I]。如果 J ≠ K 并且第 J 和第 K 圆盘至少有一个公共点,我们说第 J 个圆盘和第 K 个圆盘相交。写一个函数:class Solution { public int number_of_disc_intersections(int[] A); } ,给定一个描述 N 个圆盘的数组 A,如上所述,返回相交圆盘对的数量。
您可以在此处查看测试。
有一些明显的 O(n^2) 时间复杂度解决方案,但目标是 O(n*log(n))。
我想出了这个,它适用于我提供的任何示例,以及 codility 给出的简单测试用例( [1, 5, 2, 1, 4, 0] ),但 Codility 告诉我它在大多数情况下都失败了其他人,但我不太明白为什么。
它当然应该是 O(n log n),因为将 n 个磁盘中的每一个添加到 TreeSet 是 log n,然后我们遍历每个磁盘,只有 O(1) 操作 TreeSet.headSet()。
import java.util.*;
class Circle implements Comparable<Circle> {
long edge;
int index;
Circle (long e, int i){
edge = e;
index = i;
}
long getRightAssumingEdgeIsLeft(){
return (long)(2*index - edge + 1);
}
@Override
public int compareTo(Circle other){
return Long.valueOf(edge).compareTo(other.edge);
}
}
class Solution {
public int number_of_disc_intersections ( int[] A ) {
int N = A.length;
if (N<2) return 0;
int result = 0;
SortedSet<Circle> leftEdges = new TreeSet<Circle>();
for (int i=0; i<N; i++) {
leftEdges.add( new Circle( (long)(i-A[i]), i ) );
}
int counter = 0;
for (Circle c : leftEdges) {
long rightEdge = c.getRightAssumingEdgeIsLeft();
Circle dummyCircle = new Circle (rightEdge, -1);
SortedSet<Circle> head = leftEdges.headSet(dummyCircle);
result += head.size() - counter;
if (result > 10000000) return -1;
counter++;
}
return result;
}
}