输入是一个2n个整数的数组,它通过说明圆上的点如何配对来定义线段 和连接。 (每个点都有自己的连接对。)
数组
[2,3,0,1]
读取:点0连接到点2
点1连接到点3
点2连接到点0
点3连接到 第1点意思是我们有线段(0,2)和(1,3)。
这些点位于圆圈上,顺序与它们相同 位于阵列中。 (他们的确切坐标是无关紧要的。)
这是我的数组示例的图片。 (发生了1次交叉。)
输出是交叉点的数量。 (2个线段接触的点数。)
计算这个的最佳(最快)方法是什么?
我尝试了什么:
public static int count(int[] world) {
int i = 0;
int intersections = 0;
int endpoint = 0;
// run trought all points in order, find their pairs and check if the line they make is intersected
while (i < world.length - 1) {
if (world[i] == i+1) { // if 2 neighbouring points are connected, there are no intersections with the line they make
i++;
} else if (world[i] > i) { // don't need to check previously checked pairs
endpoint = world[i];
// check if any intersections with the line L(i,world[i]):
// This goes through all points that are located before the endpoint of the line defined by point i and its pair world[i]
// And checks if their pair is located after the endpoint, which means that the line they make intersects the line L(i,world[i])
for (int j = i+1; j < endpoint; j++) {
if (world[j] > endpoint) {
intersections++;
}
}
}
i++;
}
return intersections;
}
感谢saby的回答,我也对此进行了编码:
public static int countIntersections(int[] world) {
int intersections = 0;
for (int i = 1; i < world.length; i++) {
for (int j = 0; j < i; j++) {
if (!C(i,world[i],i-j,world[i-j])) {
intersections++;
}
}
}
return intersections;
}
public static boolean C(int a, int b, int x, int y) {
return ((a <= x && b <= x) || (a >= x && b <= y) || (a >= x && b >= x));
}
与我的初始代码相同的结果意味着它们都有效!但我的初始代码比这个快。
我会接受他的答案,因为两个代码都有效,优化问题更适合Codereview。
答案 0 :(得分:0)
观察:鉴于两个细分L1: [a, b]
和L2: [x, y]
,他们 DONT 相交,当且仅当(a < x && b > y) || (x < a && y > b)
。
请调用此条件C(L1, l2)
。
算法概要:
C(L1, L2)
。如果是假,则将交叉点数加1。C(L3, L1)
和C(L3, L2)
。相应地添加1。C(Ln, Ln-1)
,C(Ln, Ln-2)
... O(n^2)
。 n
是段数