使用TreeSet计算磁盘交叉点

use*_*973 9 java

在我将真实测试作为工作申请的一部分之前,我正在尝试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的是数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;
  }
}
Run Code Online (Sandbox Code Playgroud)

irr*_*ant 18

一种不同的算法(O(N log N)):

这个糟糕的情景图:

在此输入图像描述

可以转换为范围列表:(不完全相同的场景)

图2 在此输入图像描述

O(N log N):我们首先对标记进行排序,如果我们想将切线圆盘计算为重叠,请注意绿色标记出现在红色标记之前.

O(N):我们从total最初= 0overlaps最初开始从左到右扫描= 0.每当我们点击绿色标记时,total += 1每个红色标记处,total -= 1.此外,在每个绿色标记,if total > 0, then overlaps += total.

图2中的黑色数字表示total每一步; 橙色是overlaps.

overlaps应该是答案.

请参阅此处的粗略实现:http://ideone.com/ggiRPA

  • 这更优雅,更少混乱.它的工作原理!对于那些好奇的人,我已经在这里放了一个Java实现(http://pastebin.com/RcMNVNUr).在将其添加到重叠之后,我增加"total"的唯一微小调整("这个新圆圈与'total`现有圆圈重叠.现在有一个新的圆圈可以考虑").然后不需要`if total> 0`条件,因为`total`不再是负数.虽然可能有一个比偷看和轮询更好的方式来排队. (2认同)