任务如下:
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);
}
}
问题是我有以下结果:
我不太明白为什么我会在large_range
和large2
测试中获得这些结果。
我自己做了一个测试,应该模拟大数组:
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中的类型时会发生什么?
答案 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);
}