Algorithm to calculate number of intersecting discs

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

    O(N) complexity and O(N) memory solution.

    private static int Intersections(int[] a)
    {
        int result = 0;
        int[] dps = new int[a.length];
        int[] dpe = new int[a.length];
    
        for (int i = 0, t = a.length - 1; i < a.length; i++)
        {
            int s = i > a[i]? i - a[i]: 0;
            int e = t - i > a[i]? i + a[i]: t;
            dps[s]++;
            dpe[e]++;
        }
    
        int t = 0;
        for (int i = 0; i < a.length; i++)
        {
            if (dps[i] > 0)
            {
                result += t * dps[i];
                result += dps[i] * (dps[i] - 1) / 2;
                if (10000000 < result) return -1;
                t += dps[i];
            }
            t -= dpe[i];
        }
    
        return result;
    }
    
    0 讨论(0)
  • 2020-12-12 11:44

    A 100/100 C# implementation as described by Aryabhatta (the binary search solution).

    using System;
    
    class Solution {
        public int solution(int[] A)
        {
            return IntersectingDiscs.Execute(A);
        }
    }
    
    class IntersectingDiscs
    {
        public static int Execute(int[] data)
        {
            int counter = 0;
    
            var intervals = Interval.GetIntervals(data);
    
            Array.Sort(intervals); // sort by Left value
    
            for (int i = 0; i < intervals.Length; i++)
            {
                counter += GetCoverage(intervals, i);
    
                if(counter > 10000000)
                {
                    return -1;
                }
            }
    
            return counter;
        }
    
        private static int GetCoverage(Interval[] intervals, int i)
        {
            var currentInterval = intervals[i];
    
            // search for an interval starting at currentInterval.Right
    
            int j = Array.BinarySearch(intervals, new Interval { Left = currentInterval.Right });
    
            if(j < 0)
            {
                // item not found
    
                j = ~j; // bitwise complement (see Array.BinarySearch documentation)
    
                // now j == index of the next item larger than the searched one
    
                j = j - 1; // set index to the previous element
            }
    
            while(j + 1 < intervals.Length && intervals[j].Left == intervals[j + 1].Left)
            {
                j++; // get the rightmost interval starting from currentInterval.Righ
            }
    
            return j - i; // reduce already processed intervals (the left side from currentInterval)
        }
    }
    
    class Interval : IComparable
    {
        public long Left { get; set; }
        public long Right { get; set; }
    
        // Implementation of IComparable interface
        // which is used by Array.Sort().
        public int CompareTo(object obj)
        {
            // elements will be sorted by Left value
    
            var another = obj as Interval;
    
            if (this.Left < another.Left)
            {
                return -1;
            }
    
            if (this.Left > another.Left)
            {
                return 1;
            }
    
            return 0;
        }
    
        /// <summary>
        /// Transform array items into Intervals (eg. {1, 2, 4} -> {[-1,1], [-1,3], [-2,6]}).
        /// </summary>
        public static Interval[] GetIntervals(int[] data)
        {
            var intervals = new Interval[data.Length];
    
            for (int i = 0; i < data.Length; i++)
            {
                // use long to avoid data overflow (eg. int.MaxValue + 1)
    
                long radius = data[i];
    
                intervals[i] = new Interval
                {
                    Left = i - radius,
                    Right = i + radius
                };
            }
    
            return intervals;
        }
    }
    
    0 讨论(0)
  • A ruby solution. Scores 100%.

    def solution(a)
      # write your code in Ruby 2.2
      open = Hash.new
      close = Hash.new
    
      (0..(a.length-1)).each do |c|
        r = a[c]
        open[ c-r ]  ? open[ c-r ]+=1  : open[ c-r ]=1
        close[ c+r ] ? close[ c+r ]+=1 : close[ c+r ]=1 
      end
    
      open_now = 0
      intersections = 0
      open.merge(close).keys.sort.each do |v|
        intersections += (open[v]||0)*open_now
        open_now += (open[v]||0) - (close[v]||0)
        if(open[v]||0)>1
          # sum the intersections of only newly open discs
          intersections += (open[v]*(open[v]-1))/2
          return -1 if intersections > 10000000
        end
      end
      intersections
    end
    
    0 讨论(0)
  • 2020-12-12 11:46

    Java 2*100%.

    result is declared as long for a case codility doesn't test, namely 50k*50k intersections at one point.

    class Solution {
        public int solution(int[] A) {
    
            int[] westEnding = new int[A.length];
            int[] eastEnding = new int[A.length];
    
            for (int i=0; i<A.length; i++) {
                if (i-A[i]>=0) eastEnding[i-A[i]]++; else eastEnding[0]++;
                if ((long)i+A[i]<A.length) westEnding[i+A[i]]++; else westEnding[A.length-1]++;
            }
    
            long result = 0; //long to contain the case of 50k*50k. codility doesn't test for this.
            int wests = 0;
            int easts = 0;
            for (int i=0; i<A.length; i++) {
    
                int balance = easts*wests; //these are calculated elsewhere
    
                wests++;
                easts+=eastEnding[i];
    
                result += (long) easts*wests - balance - 1; // 1 stands for the self-intersection
                if (result>10000000) return -1;
    
                easts--;
                wests-= westEnding[i];
            }
    
            return (int) result;
        }
    }
    
    0 讨论(0)
  • 2020-12-12 11:46

    My answer in Swift; gets a 100% score.

    import Glibc
    
    struct Interval {
        let start: Int
        let end: Int
    }
    
    func bisectRight(intervals: [Interval], end: Int) -> Int {
        var pos = -1
        var startpos = 0
        var endpos = intervals.count - 1
    
        if intervals.count == 1 {
            if intervals[0].start < end {
                return 1
            } else {
                return 0
            }
        }
    
        while true {
            let currentLength = endpos - startpos
    
            if currentLength == 1 {
                pos = startpos
                pos += 1
                if intervals[pos].start <= end {
                    pos += 1
                }
                break
            } else {
                let middle = Int(ceil( Double((endpos - startpos)) / 2.0 ))
                let middlepos = startpos + middle
    
                if intervals[middlepos].start <= end {
                    startpos = middlepos
                } else {
                    endpos = middlepos
                }
            }
        }
    
        return pos
    }
    
    public func solution(inout A: [Int]) -> Int {
        let N = A.count
        var nIntersections = 0
    
        // Create array of intervals
        var unsortedIntervals: [Interval] = []
        for i in 0 ..< N {
            let interval = Interval(start: i-A[i], end: i+A[i])
            unsortedIntervals.append(interval)
        }
    
        // Sort array
        let intervals = unsortedIntervals.sort {
            $0.start < $1.start
        }
    
        for i in 0 ..< intervals.count {
            let end = intervals[i].end
    
            var count = bisectRight(intervals, end: end)
    
            count -= (i + 1)
            nIntersections += count
    
            if nIntersections > Int(10E6) {
                return -1
            }
        }
    
        return nIntersections
    }
    
    0 讨论(0)
  • 2020-12-12 11:49

    I got 100 out of 100 with this C++ implementation:

    #include <map>
    #include <algorithm>
    
    inline bool mySortFunction(pair<int,int> p1, pair<int,int> p2)
    {
        return ( p1.first < p2.first );
    }
    
    int number_of_disc_intersections ( const vector<int> &A ) {
        int i, size = A.size();
        if ( size <= 1 ) return 0;
        // Compute lower boundary of all discs and sort them in ascending order
        vector< pair<int,int> > lowBounds(size);
        for(i=0; i<size; i++) lowBounds[i] = pair<int,int>(i-A[i],i+A[i]);
        sort(lowBounds.begin(), lowBounds.end(), mySortFunction);
        // Browse discs
        int nbIntersect = 0;
        for(i=0; i<size; i++)
        {
            int curBound = lowBounds[i].second;
            for(int j=i+1; j<size && lowBounds[j].first<=curBound; j++)
            {
                nbIntersect++;
                // Maximal number of intersections
                if ( nbIntersect > 10000000 ) return -1;
            }
        }
        return nbIntersect;
    }
    
    0 讨论(0)
提交回复
热议问题