Algorithm to calculate number of intersecting discs

前端 未结 30 1380
鱼传尺愫
鱼传尺愫 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:39

    So you want to find the number of intersections of the intervals [i-A[i], i+A[i]].

    Maintain a sorted array (call it X) containing the i-A[i] (also have some extra space which has the value i+A[i] in there).

    Now walk the array X, starting at the leftmost interval (i.e smallest i-A[i]).

    For the current interval, do a binary search to see where the right end point of the interval (i.e. i+A[i]) will go (called the rank). Now you know that it intersects all the elements to the left.

    Increment a counter with the rank and subtract current position (assuming one indexed) as we don't want to double count intervals and self intersections.

    O(nlogn) time, O(n) space.

    0 讨论(0)
  • 2020-12-12 11:40

    Thanks to Falk for the great idea! Here is a ruby implementation that takes advantage of sparseness.

    def int(a)
    
        event = Hash.new{|h,k| h[k] = {:start => 0, :stop => 0}}
        a.each_index {|i|
            event[i - a[i]][:start] += 1
            event[i + a[i]][:stop ] += 1
        }
        sorted_events = (event.sort_by {|index, value| index}).map! {|n| n[1]}
    
        past_start = 0
        intersect = 0
    
        sorted_events.each {|e|
    
            intersect += e[:start] * (e[:start]-1) / 2 +
                         e[:start] * past_start
    
            past_start += e[:start]
            past_start -= e[:stop]
        }
        return intersect
    end
    
    puts int [1,1]
    
    puts int [1,5,2,1,4,0]
    
    0 讨论(0)
  • 2020-12-12 11:41

    C# solution 100/100

    using System.Linq;
    
    class Solution
    {
        private struct Interval
        {
            public Interval(long @from, long to)
            {
                From = @from;
                To = to;
            }
    
            public long From { get; }
            public long To { get; }
        }
    
        public int solution(int[] A)
        {
            int result = 0;
    
            Interval[] intervals = A.Select((value, i) =>
            {
                long iL = i;
                return new Interval(iL - value, iL + value);
            })
            .OrderBy(x => x.From)
            .ToArray();
    
            for (int i = 0; i < intervals.Length; i++)
            {
                for (int j = i + 1; j < intervals.Length && intervals[j].From <= intervals[i].To; j++)
                    result++;
    
                if (result > 10000000)
                    return -1;
            }
    
            return result;
        }
    }
    
    0 讨论(0)
  • 2020-12-12 11:42

    Swift 4 Solution 100% (Codility do not check the worst case for this solution)

    public func solution(_ A : inout [Int]) -> Int {
        // write your code in Swift 4.2.1 (Linux)
        var count = 0
        let sortedA = A.sorted(by: >)
        if sortedA.isEmpty{ return 0 }
        let maxVal = sortedA[0]
    
        for i in 0..<A.count{
            let maxIndex = min(i + A[i] + maxVal + 1,A.count)
            for j in i + 1..<maxIndex{
                if j - A[j] <= i + A[i]{
                    count += 1
                }
            }
    
            if count > 10_000_000{
                return -1
            }
        }
    
        return count
    }
    
    0 讨论(0)
  • 2020-12-12 11:42
    #include <stdio.h>
    #include <stdlib.h>
    void sortPairs(int bounds[], int len){
        int i,j, temp;
        for(i=0;i<(len-1);i++){
            for(j=i+1;j<len;j++){
                if(bounds[i] > bounds[j]){
                    temp = bounds[i];
                    bounds[i] = bounds[j];
                    bounds[j] = temp;
                    temp = bounds[i+len];
                    bounds[i+len] = bounds[j+len];
                    bounds[j+len] = temp;
                }
            }
        }
    }
    int adjacentPointPairsCount(int a[], int len){
        int count=0,i,j;
        int *bounds;
        if(len<2) {
            goto toend;
        }
        bounds = malloc(sizeof(int)*len *2);
        for(i=0; i< len; i++){
            bounds[i] = i-a[i];
            bounds[i+len] = i+a[i];
        }
        sortPairs(bounds, len);
        for(i=0;i<len;i++){
            int currentBound = bounds[i+len];
            for(j=i+1;a[j]<=currentBound;j++){
                if(count>100000){
                    count=-1;
                    goto toend;
                }
                count++;
            }     
        }
    toend:
        free(bounds);
        return count;   
    }
    
    0 讨论(0)
  • 2020-12-12 11:43

    This is a ruby solution that scored 100/100 on codility. I'm posting it now because I'm finding it difficult to follow the already posted ruby answer.

    def solution(a)
        end_points = []
        a.each_with_index do |ai, i|
            end_points << [i - ai, i + ai]
        end
        end_points = end_points.sort_by { |points| points[0]}
    
        intersecting_pairs = 0
        end_points.each_with_index do |point, index|
            lep, hep = point
            pairs = bsearch(end_points, index, end_points.size - 1, hep)
            return -1 if 10000000 - pairs + index < intersecting_pairs
            intersecting_pairs += (pairs - index)
        end
        return intersecting_pairs
    end
    
    # This method returns the maximally appropriate position
    # where the higher end-point may have been inserted.
    def bsearch(a, l, u, x)
        if l == u
            if x >= a[u][0]
                return u
            else
                return l - 1 
            end
        end
        mid = (l + u)/2
    
        # Notice that we are searching in higher range
        # even if we have found equality.
        if a[mid][0] <= x
            return bsearch(a, mid+1, u, x)
        else
            return bsearch(a, l, mid, x)
        end
    end
    
    0 讨论(0)
提交回复
热议问题