0

I am trying to solve a problem stated as follows: given a set segments, and a set of points, calculate how many segments contain each point.

The problem that I have encounterd is when I have to count how many times a point is contained by a segment. When I have a certain input, the inner loop, increments correctly the counter of each point, weather when I have another data set, where comparing zero with a negative number and a non-negative number takes place, it behaves strangely.

The following is just a script created to locate the problem that I am facing, and does not represent the actual implementation.

The test cases give the outputs as follow:

Case 1:

    String debug = "Test case 1: \n ";
    debug += " \n - 2 Segments with coordinates [0, 5] and [7, 10].";
    debug += " \n - 3 points at the coordinates 1, 6, and 11.";
    int [] starts = new int[]{0, 7};
    int [] ends = new int[]{5, 10};
    int [] points = new int[]{1, 6, 11};

    debug += "\n \n Calculating the coverage of the points: ";
    for ( int i=0; i<starts.length; i++) {
        for (int j=0; j<points.length && ( starts[i] <= points[j] && points[j] <= ends[i]); j++) {
            debug += " \n * Point with coordinate " + points[j] + ", is between " + starts[i] + " and " + ends[i];
        }
    }
    debug += "\n \n FINISHED the calculation!";

    int start = 0, point = 1, end = 5;
    debug += "\n \n Custom check for the 1st point: ";
    debug += "\n - Is (" + start + " <= " + point + " and " + point + " <= " + end + ")? " + ( start <= point && point <= end );
    System.out.println(debug);

Output:

Test case 1:

  • 2 Segments with coordinates [0, 5] and [7, 10].
  • 3 points at the coordinates 1, 6, and 11.

    Calculating the coverage of the points:

  • Point with coordinate 1, is between 0 and 5

    FINISHED the calculation!

    Custom check for the 1st point:

  • Is (0 <= 1 and 1 <= 5)? true

Case 2:

    String debug = "Test case 2: \n ";
    debug += " \n - 1 Segment with coordinates [-10, 10].";
    debug += " \n - 3 points at the coordinates -100, 100, and 10.";
    int [] starts = new int[]{-10};
    int [] ends = new int[]{10};
    int [] points = new int[]{-100, 100, 0};

    debug += "\n \n Calculating the coverage of the points: ";
    for ( int i=0; i<starts.length; i++) {
        for (int j=0; j<points.length && ( starts[i] <= points[j] && points[j] <= ends[i]); j++) {
            debug += " \n * Point with coordinate " + points[j] + ", is between " + starts[i] + " and " + ends[i];
        }
    }
    debug += "\n \n FINISHED the calculation!";

    int start = -10, point = 0, end = 10;
    debug += "\n \n Custom check: ";
    debug += "\n - Is (" + start + " <= " + point + " and " + point + " <= " + end + ")? " + ( start <= point && point <= end );
    System.out.println(debug);

Output:

Test case 2:

  • 1 Segment with coordinates [-10, 10].
  • 3 points at the coordinates -100, 100, and 10.

    Calculating the coverage of the points:

    FINISHED the calculation!

    Custom check:

  • Is (-10 <= 0 and 0 <= 10)? true

As you can see, the condition at the inner loop is somehow not calculating appropriately the case of the point with coordinate 0, relative to the segment [-10, 10].

Thanks in advance, Endrit.

Endrit Sino
  • 113
  • 4

2 Answers2

0

Your problem is with your for loop condition:

for (int j=0; j<points.length && ( starts[i] <= points[j] && points[j] <= ends[i]); j++) {

As soon as you encounter any point[j] that does not lie between starts[i] and ends[i] then the loop will terminate and you won't check any subsequent points.

Instead, you should separate the loop condition from the intersection condition. In pseudocode:

for every (start, end) pair:
    for every point:
         if point intersects (start, end):
              increment counter
         otherwise continue to next point

Does that make sense?

Daniel Pryden
  • 59,486
  • 16
  • 97
  • 135
  • I totally agree with you, but that's precisely why I choose this approach, which means, that the complexity would increase exponentially. That's why I tried to implement this type of condition, in order to obtain a "smart" selection of the points to increment, right from the for condition. – Endrit Sino Nov 06 '16 at 01:00
0

To reduce the big-O order from points.Length * ends.Length, you can loop through the both at the same time. I'm assuming segments cannot overlap.

Array.sort(starts);
Array.sort(ends);
Array.sort(points);
int pointIndex = 0;
String debug = ""
int numCollisions = 0;
bool collides = False;
for (int i=0; i < ends.length; i++) {
    debug += "Points between " + starts[i] + " and " + ends[i] ":\n";
    while (pointIndex < points.Length && points[pointIndex] < starts[i]) {
        pointIndex++;
    }
    while (pointIndex < points.Length && points[pointIndex] <= ends[i]) {
        numCollisions++;
        debug += "    " + points[pointIndex] "\n";
        pointIndex++;
    }
}
debug += "Total number of collisions: " + numCollisions;
System.out.println(debug);

// Original Response:

In Test Case 2, you exit the for loop on the 2nd iteration of the inner loop (i==0 and j==1) because points[j] == 100 and ends[i] == 10. Since you've exited the loop, 0 never gets checked.

Try sorting points before entering the for loop.

Michael
  • 1
  • 3
  • I might say that if you see the result and execute the first case, the loop works perfectly. What's more, even if you sort the loop, you get the same result. The inner for doesn't execute approiprately the debug stamp. – Endrit Sino Nov 06 '16 at 01:02
  • In Test Case 1, the `points` is already sorted, so it executes correctly. In Test Case 2, it exits the inner loop prematurely. The 'debug' check does not have stop executing I'm not sure what you mean by "sort the loop", but – Michael Nov 06 '16 at 23:47
  • Sorry, I hit enter without meaning to. If you sort the list before the entering the outer for loop, the internal one will not exit prematurely. That said, the big O order of this algorithm is still [num points] * [num segments], same as the solution offered by @DanielPryder. To improve the big-O order, you basically have eliminate the nested for loop. – Michael Nov 06 '16 at 23:56
  • Yes, Michael I am aware of that, but what I want, is to efficiently calculate the counter of each point, by taking into consideration only the points within the interval [start, end]. If I choose the @DanielPryder's method, for each segment the algorithm will control if the point is covered by the segment or not. Which is not efficient for me. P.S. "sort the loop", was the wrong way of expression by me, I meant sorting the sequence of the points, taken into consideration by the second for Loop. – Endrit Sino Nov 07 '16 at 09:03
  • I've edited my answer to add a solution which eliminates the nested loops. Does that solve the issue? – Michael Nov 07 '16 at 13:10
  • Michael thanks for your feedback again. I am affraid that your solution is not correct. Try a test case with 3 segments: [-3, 2], [0, 5], and [7, 10], and 2 points, with coordinates 1 and 6. It should return 2 for the first point, but instead it returns only 1. – Endrit Sino Nov 07 '16 at 14:45
  • Ah, you've given it overlapping segments. I had assumed that was not allowed. – Michael Nov 07 '16 at 14:51