2

My code is timing out as it is inefficient. Program takes in a line of n integers. Each consecutive pair of integers represents a single point (x, y) this is an example of input :

-5 -10 20 25 30 2 -1 -40

Output:

java.awt.Point[x=-5,y=-10]
java.awt.Point[x=-1,y=-40]
java.awt.Point[x=20,y=25]
java.awt.Point[x=30,y=2]
4

I have the code to sort all the points. They are sorted from smallest to biggest. Where "x" values are equal, I then check the y value. The PROBLEM is this: I need to count how many times a point is bigger than every other point (both x and y). So in the above example, the answer is 4.

  • The fourth point is bigger than the first and second point.

  • The third point is bigger than the first and second.

    Which results in 4.

If points are equal, also increase the counter.

For really really longer line of integers, my program times out (killed). I can't provide the input here as it is way too long. How else can I improve the complexity?

public void calculateDomination(){
        int counter =0;
        int sizeOfList = this.coordinateList.size();
        for(int i = 0; i < sizeOfList ; i++){
            for(int j = i+1; j < sizeOfList ; j++){
                if(((this.coordinateList.get(i).x) < (this.coordinateList.get(j).x)) && ((this.coordinateList.get(i).y) < (this.coordinateList.get(j).y)) ){
                    counter++;
                }
                else if(((this.coordinateList.get(i).x) == (this.coordinateList.get(j).x)) && ((this.coordinateList.get(i).y) == (this.coordinateList.get(j).y)) ){
                    counter++;
                }
            }
        }
        System.out.println(counter);
    }
Community
  • 1
  • 1
Jay Jay
  • 57
  • 1
  • 11
  • I did quite understand the logic for your algorithm but you can chnage these in your code to make it more efficient: 1) Move 'smaller then' and 'equal' checks into the same 'if' statement: `this.coordinateList.get(i).x) <= (this.coordinateList.get(j).x)` 2) `get` operation on list can be expensive, better get the object from the list and then access `x` or `y` on it. – tsolakp Oct 25 '17 at 22:18
  • Also, no need to compare `x` at all, since you are only testing the points that come after the current one in the sorted list. Does not decrease the overall complexity, though, which is still O(n²). – tobias_k Oct 25 '17 at 22:22
  • @tsolakp Is there anything I can explain to help you understand it more? I'm not too sure If I understand what you mean by your second point. Please can you explain it. – Jay Jay Oct 25 '17 at 22:36
  • @tobias_k Any other way I can decrease the complexity? – Jay Jay Oct 25 '17 at 22:37
  • I meant something like this: `YourWhateverObject o1 = this.coordinateList.get(i); YourWhateverObject o2 = this.coordinateList.get(j); if( (o1.x <= o2.x) && (o1.y <= o2.y) ){ counter++; }` – tsolakp Oct 25 '17 at 22:40
  • @tsolakp That only makes a difference if list access is O(n), but in this case, it would be more efficient to just convert the entire list to a form with O(1) access first. – tobias_k Oct 26 '17 at 07:43

1 Answers1

2

The first idea I posted, now removed, would not actually work. The one that does work:

Use an incremental sorting/counting of encountered y values:

As you go through the list, maintain a TreeMultiset of all the y values encountered so far. At each point, check the size() of the headMultiset() of nodes before the current y value. Since only values from points with lower x values will have been added to it yet, that will give you the current point's count.

I think all involved operations of TreeMultiset are O(log(n)), so this will drop your algorithm from O(n^2) to O(n * log(n)).

Douglas
  • 5,017
  • 1
  • 14
  • 28