Algorithm to calculate number of intersecting discs

前端 未结 30 1516
鱼传尺愫
鱼传尺愫 2020-12-12 10:57

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

30条回答
  •  眼角桃花
    2020-12-12 11:51

    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.

提交回复
热议问题