NumberOfDiscIntersections在codility测试中溢出

时间:2015-05-28 04:49:21

标签: java algorithm

在编纂测试中NumberOfDiscIntersections我得到了100%的正确率和87%的正确率,其中一次测试失败了

overflow
arithmetic overflow tests
got -1 expected 2

我无法看到导致我使用的是64位长的原因。即使我能100%达到100%正确性,我想知道是否有更好的方法来做到这一点,而不是Java中的冗长。

编辑:找出一个更好的方法来处理两个数组而不是一对类

// you can also use imports, for example:
 import java.util.*;

// you can use System.out.println for debugging purposes, e.g.
// System.out.println("this is a debug message");

class Solution {
    public int solution(int[] A) {
        int j = 0;
        Pair[] arr = new Pair[A.length * 2];
        for (int i = 0; i < A.length; i++) {
            Pair s = new Pair(i - A[i], true);
            arr[j] = s;
            j++;
            Pair e = new Pair(i + A[i], false);
            arr[j] = e;
            j++;
        }
        Arrays.sort(arr, new Pair(0, true));

        long numIntersect = 0;
        long currentCount = 0;
        for (Pair p: arr) {
            if (p.start) {
                numIntersect += currentCount;
                if (numIntersect > 10000000) {
                    return -1;
                }
                currentCount++;
            } else {
                currentCount--;
            }
        }

        return (int) numIntersect;
    }

    static private class Pair implements Comparator<Pair> {
        private long x;
        private boolean start;
        public Pair(long x, boolean start) {
            this.x = x;
            this.start = start;
        }

        public int compare(Pair p1, Pair p2) {
            if (p1.x < p2.x) {
                return -1;
            } else if (p1.x > p2.x) {
                return 1;
            } else {
                if (p1.start && p2.start == false) {
                    return -1;
                } else if (p1.start == false && p2.start) {
                    return 1;
                } else {
                    return 0;
                }
            }
        }
    }
}

5 个答案:

答案 0 :(得分:1)

看看这一行:

Pair s = new Pair(i + A[i], true);

这相当于Pair s = new Pair((long)(i + A[i]) , true);

由于i是整数,A[i]也是整数,因此这可能会导致溢出,因为A[i]中的值最多可以达到Integer.MAX_VALUE,并且转换为添加操作完成后发生了long

修复:

Pair s = new Pair((long)i + (long)A[i], true);

注意:我已经提交了我的固定版并获得了100%

https://codility.com/demo/results/demoRRBY3Q-UXH/

答案 1 :(得分:1)

我今天的解决方案。 O(N)时间复杂度。简单假设表的下一个点中的可用对数是该时刻的总开放圆(圆)与之前已处理过的圆之间的差。也许很简单:)

  public int solution04(int[] A) { 
    final int N = A.length;
    final int M = N + 2;
    int[] left  = new int[M]; // values of nb of "left"  edges of the circles in that point
    int[] sleft = new int[M]; // prefix sum of left[]
    int il, ir;               // index of the "left" and of the "right" edge of the circle

    for (int i = 0; i < N; i++) { // counting left edges
      il = tl(i, A);
      left[il]++;
    }

    sleft[0] = left[0];
    for (int i = 1; i < M; i++) {// counting prefix sums for future use
      sleft[i]=sleft[i-1]+left[i];
    }
    int o, pairs, total_p = 0, total_used=0;
    for (int i = 0; i < N; i++) { // counting pairs
      ir = tr(i, A, M);
      o  = sleft[ir];                // nb of open till right edge
      pairs  = o -1 - total_used;
      total_used++;
      total_p += pairs;
    }
    if(total_p > 10000000){
      total_p = -1;
    }
    return total_p;
  }

  int tl(int i, int[] A){
    int tl = i - A[i]; // index of "begin" of the circle
      if (tl < 0) {
        tl = 0;
      } else {
        tl = i - A[i] + 1;
      }
    return tl;
  }
  int tr(int i, int[] A, int M){
    int tr;           // index of "end" of the circle
      if (Integer.MAX_VALUE - i < A[i] || i + A[i] >= M - 1) {
        tr = M - 1;
      } else {
        tr = i + A[i] + 1;
      }
      return tr;
  }

答案 2 :(得分:0)

我对此表示赞同,O(n):

public int solution(int[] A) {

    int[] startPoints = new int[A.length];
    int[] endPoints = new int[A.length];
    int tempPoint;

    int currOpenCircles = 0;
    long pairs = 0;

    //sum of starting and end points - how many circles open and close at each index?
    for(int i = 0; i < A.length; i++){
        tempPoint = i - A[i];
        startPoints[tempPoint < 0 ? 0 : tempPoint]++;
        tempPoint = i + A[i];
        if(A[i] < A.length && tempPoint < A.length) //first prevents int overflow, second chooses correct point
            endPoints[tempPoint]++;
    }

    //find all pairs of new circles (combinations), then make pairs with exiting circles (multiplication)
    for(int i = 0; i < A.length; i++){

        if(startPoints[i] >= 2)
            pairs += (startPoints[i] * (startPoints[i] - 1)) / 2;

        pairs += currOpenCircles * startPoints[i];

        currOpenCircles += startPoints[i];
        currOpenCircles -= endPoints[i];

        if(pairs > 10000000) 
            return -1;
    }

    return (int) pairs;
}

答案 3 :(得分:0)

Helsing解决方案部分的解释:

if(startPoints[i] >= 2) pairs += (startPoints[i] * (startPoints[i] - 1)) / 2; 

基于数学组合公式:

Cn,m = n! / ((n-m)!.m!

对于配对,则m = 2,然后:

Cn,2 = n! / ((n-2)!.2

等于:

Cn,2 = n.(n-1).(n-2)! / ((n-2)!.2

通过简化:

Cn,2 = n.(n-1) / 2

答案 4 :(得分:0)

性能不是很好,但是使用流。

List<Long> list = IntStream.range(0, A.length).mapToObj(i -> Arrays.asList((long) i - A[i], (long) i + A[i]))
            .sorted((o1, o2) -> {
                int f = o1.get(0).compareTo(o2.get(0));
                return f == 0 ? o1.get(1).compareTo(o2.get(1)) : f;
            })
            .collect(ArrayList<Long>::new,
                    (acc, val) -> {
                        if (acc.isEmpty()) {
                            acc.add(0l);
                            acc.add(val.get(1));
                        } else {
                            Iterator it = acc.iterator();
                            it.next();
                            while (it.hasNext()) {
                                long el = (long) it.next();
                                if (val.get(0) <= el) {
                                    long count = acc.get(0);
                                    acc.set(0, ++count);
                                } else {
                                    it.remove();
                                }
                            }
                            acc.add(val.get(1));
                        }
                    },
                    ArrayList::addAll);
    return (int) (list.isEmpty() ? 0 : list.get(0) > 10000000 ? -1 : list.get(0));