Number of Disc Intersection

Problem

We draw N discs on a plane. The discs are numbered from 0 to N − 1. An array A of N non-negative integers, specifying the radiuses of the discs, is given. The J-th disc is drawn with its center at (J, 0) and radius A[J].

We say that the J-th disc and K-th disc intersect if J ≠ K and the J-th and K-th discs have at least one common point (assuming that the discs contain their borders).

The figure below shows discs drawn for N = 6 and A as follows:

A[0] = 1
A[1] = 5
A[2] = 2
A[3] = 1
A[4] = 4
A[5] = 0

image

There are eleven (unordered) pairs of discs that intersect, namely:

  • discs 1 and 4 intersect, and both intersect with all the other discs;
  • disc 2 also intersects with discs 0 and 3.

Write a function:

function solution(A);

that, given an array A describing N discs as explained above, returns the number of (unordered) pairs of intersecting discs. The function should return −1 if the number of intersecting pairs exceeds 10,000,000.

Given array A shown above, the function should return 11, as explained above.

Write an efficient algorithm for the following assumptions:

  • N is an integer within the range [0..100,000];
  • each element of array A is an integer within the range [0..2,147,483,647].

My Solution

success O(N * log(N))
function solution(A) {
	let counter = 0;
	let j = 0;
	let leftLimit = [];
	let rightLimit = [];

	//fill the left and right limits of each circle
	for (var i = 0; i < A.length; i++) {
		leftLimit[i] = i - A[i];
		rightLimit[i] = i + A[i];
	}

	//sort them in an ascending order - why ?
	//Basically we will rearrange their limits in an ascending way,
	//we will have in leftLimit all open circles while  in the right we will have where the next circle closes
	leftLimit.sort((a, b) => a - b);
	rightLimit.sort((a, b) => a - b);

	//loop through all the elements of the RIGHT boundaries
	for (var i = 0; i < A.length; i++) {
		//this is the tricky part to understand
		//on the left we have the boundaries of open circles, on the right the boundary of the next circle
		//as long as there are circles open (rightLimit[i] >= leftLimit[j]) and (j < A.length)
		while (j < A.length && rightLimit[i] >= leftLimit[j]) {
			//we have circles at each position,
			//so, as long as the left boundaries are smaller or equal to the right boundary, there are circles intersecting there
			//if j surpasses j, it means we overcalculated and we start to decrease the number of intersections
			counter += j - i;
			//pass to the next open circle
			j++;
		}

		if (counter > 10000000) return -1;
	}

	return counter;
}