Codility PermMissingElem给出了奇怪的结果

时间:2015-01-09 19:11:49

标签: java

任务如下:

A zero-indexed array A consisting of N different integers is given. The array contains integers in the range [1..(N + 1)], which means that exactly one element is missing.
Your goal is to find that missing element.
Write a function:
class Solution { public int solution(int[] A); }
that, given a zero-indexed array A, returns the value of the missing element.
For example, given array A such that:
  A[0] = 2
  A[1] = 3
  A[2] = 1
  A[3] = 5
the function should return 4, as it is the missing element.
Assume that:
N is an integer within the range [0..100,000];
the elements of A are all distinct;
each element of array A is an integer within the range [1..(N + 1)].
Complexity:
expected worst-case time complexity is O(N);
expected worst-case space complexity is O(1), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.

现在,我的解决方案如下:

// 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) {
        long nPlusOneSum = (A.length + 2) * (A.length + 1) / 2;
        long arraySum = 0;
        for (int element : A)
            arraySum += element;
        return (int)(nPlusOneSum - arraySum);
    }
}

问题是我有以下结果:

enter image description here

我不太明白为什么我会在large_rangelarge2测试中获得这些结果。

我自己做了一个测试,应该模拟大数组:

import org.junit.Before;
import org.junit.Test;

public class SomeOtherTest {
    int[] maxArray;
    int N = 100000;

    @Before
    public void setUp() {
        maxArray = new int[N];
        for (int i = 0; i < maxArray.length; i ++) {
            maxArray[i] = i + 1;
        }
        maxArray[0] = maxArray.length + 1;
    }


    @Test
    public void test() {
        System.out.println(solution(maxArray));

    }


    public int solution(int[] A) {
        long nPlusOneSum = (A.length + 2) * (A.length + 1) / 2;
        long arraySum = 0;
        for (int element : A)
            arraySum += element;
        return (int)(nPlusOneSum - arraySum);
    }
}

但是它为我提供了正确的答案1(使用jdk 1.8中的东西,如同编纂一样)

指向测试结果的链接:https://codility.com/demo/results/demoWAS9FA-5FA/

修改

此解决方案:

class Solution {
    public int solution(int[] A) {
        long nPlusOneSum = (A.length + 2) * (A.length + 1) / 2;
        for (int element : A)
            nPlusOneSum -= element;
        return (int)nPlusOneSum;
    }
}

给出相同的结果:https://codility.com/demo/results/demoWAS9FA-5FA/

EDIT2

一旦我引入临时变量来保存数组长度,测试就通过了 代码:

class Solution {
    public int solution(int[] A) {
        long numberOfElementsPlusOne = A.length + 1;
        long nPlusOneSum = numberOfElementsPlusOne * (numberOfElementsPlusOne + 1) / 2;
        for (int element : A)
            nPlusOneSum -= element;
        return (int)nPlusOneSum;
    }
}

结果:https://codility.com/demo/results/demoE82PUM-JCA/

EDIT3

奇怪的是,测试仍能产生正确的结果,即使在评估期间,也会发生溢出。

nPlusOneSum溢出并获得值705182705而不是5000150001

arraySum不会溢出并获得5000150000

的值

然后在return语句nPlusOneSum - arraySum被评估为-4294967295,由于某种原因,转换为(int)后会得到正确的值1

当操作溢出它在java中的类型时会发生什么?

3 个答案:

答案 0 :(得分:2)

根据java lang规范: http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.17

  

乘法表达式的类型是其提升类型   操作数

因此得到的两个int的乘法类型也​​是一个int,它默认溢出大约100.000的值,解决方案是将操作数的类型更改为long。

编辑

奇怪的是,测试仍能产生正确的结果,即使在评估期间,也会发生溢出。

答案 1 :(得分:0)

这里有很小的捕获和它: 假设您的阵列长度为100,000。您试图使用公式(N *(N + 1))/ 2找到总和,即(100,000 * 100,101)/ 2。所以这里它将两个已经超过Max数据类型值的数字相乘。因此,您已经看到了错误。

  public int solution(int[] arr) {
    int realLen = arr.length + 1;
    long realSum = 0;
    if(realLen%2 == 0) {
        realSum = (realLen/2) * (realLen + 1);
    } else {
        realSum = realLen * ((realLen + 1)/2);
    }
    for(int i = 0; i < arr.length; i++) {
        realSum = realSum - arr[i];
    }

    return (int)realSum;
}

答案 2 :(得分:0)

诀窍是A.length是整数。在使用之前,您应该将其转换为long

public int solution(int[] A) {
    long sum = 0;
    for (int element: A) {
        sum += element;
    }

    long expectedSum = (((long) A.length + 1) * ((long) A.length + 2)) / 2;

    return (int) (expectedSum - sum);
}