Given an array A of N integers we draw N discs in a 2D plane, such that i-th disc has center in (0,i) and a radius
Below is an implementation of the accepted answer by @Aryabhatta in Kotlin so all the credit goes @Aryabhatta
fun calculateDiscIntersections(A: Array): Int {
val MAX_PAIRS_ALLOWED = 10_000_000L
//calculate startX and endX for each disc
//as y is always 0 so we don't care about it. We only need X
val ranges = Array(A.size) { i ->
calculateXRange(i, A[i])
}
//sort Xranges by the startX
ranges.sortBy { range ->
range.start
}
val starts = Array(ranges.size) {index ->
ranges[index].start
}
var count = 0
for (i in 0 until ranges.size) {
val checkRange = ranges[i]
//find the right most disc whose start is less than or equal to end of current disc
val index = bisectRight(starts, checkRange.endInclusive, i)
//the number of discs covered by this disc are:
//count(the next disc/range ... to the last disc/range covered by given disc/range)
//example: given disc index = 3, last covered (by given disc) disc index = 5
//count = 5 - 3 = 2
//because there are only 2 discs covered by given disc
// (immediate next disc with index 4 and last covered disc at index 5)
val intersections = (index - i)
//because we are only considering discs intersecting/covered by a given disc to the right side
//and ignore any discs that are intersecting on left (because previous discs have already counted those
// when checking for their right intersects) so this calculation avoids any duplications
count += intersections
if (count > MAX_PAIRS_ALLOWED) {
return -1
}
}
return if (count > MAX_PAIRS_ALLOWED) {
-1
} else {
count
}
}
private fun calculateXRange(x: Int, r: Int): LongRange {
val minX = x - r.toLong()
val maxX = x + r.toLong()
return LongRange(minX, maxX)
}
fun bisectRight(array: Array, key: Long, arrayStart: Int = 0): Int {
var start = arrayStart
var end = array.size - 1
var bisect = start
while (start <= end) {
val mid = Math.ceil((start + end) / 2.0).toInt()
val midValue = array[mid]
val indexAfterMid = mid + 1
if (key >= midValue) {
bisect = mid
}
if (key >= midValue && (indexAfterMid > end || key < array[indexAfterMid])) {
break
} else if (key < midValue) {
end = mid - 1
} else {
start = mid + 1
}
}
return bisect
}
Codility Solution with 100% score.