Java 8 Stream.sum()的错误行为

May*_*rni 3 java algorithm java-8

今天在HackerRank上解决这个问题时,我使用了Array stream .sum()函数对所有条目求和并继续我的算法.但总而言之,我发现我的算法在某些情况下失败了.我使用diff来发现它通过了99%的情况,1%的输出几乎相等,但小于原始答案.这就是为什么我用for循环替换了流.sum(),并且意外地它通过了所有的测试用例.我试过但无法确定这种不确定的行为.

我使用stream.sum()的实现:

public class MandragoraForest {

    public static void main(String[] args) {
        InputReader in = new InputReader(System.in);
        for (int i = in.nextInt(); i > 0; i--) {
            int number = in.nextInt();
            int[] h = new int[number];
            for (int j = 0; j < number; j++) h[j] = in.nextInt();
            System.out.println(new MandragoraForestSolver().solve(h));
        }
    }
}

class MandragoraForestSolver {

    public long solve(int[] h) {
        if (h.length==1) return h[0];
        Arrays.parallelSort(h);
        long sum = Arrays.stream(h)
                .sum();
        long ans = -1;

        for (long i=0, strength = 2; i<h.length; i++, strength++) {
            sum -= h[(int)i];
            ans = Math.max(ans, strength * sum);
        }
        return ans;
    }
}
Run Code Online (Sandbox Code Playgroud)

没有Java流的实现:

public class MandragoraForest {

    public static void main(String[] args) {
        InputReader in = new InputReader(System.in);
        for (int i = in.nextInt(); i > 0; i--) {
            int number = in.nextInt();
            int[] h = new int[number];
            long sum = 0;
            for (int j = 0; j < number; j++) {
                h[j] = in.nextInt();
                sum += h[j];
            }
            System.out.println(new MandragoraForestSolver().solve(h, sum));
        }
    }
}

class MandragoraForestSolver {

    public long solve(int[] h, long sum) {
        if (h.length==1) return h[0];
        Arrays.parallelSort(h);


        long ans = -1;

        for (long i=0, strength = 2; i<h.length; i++, strength++) {
            sum -= h[(int)i];
            ans = Math.max(ans, strength * sum);
        }
        return ans;
    }
}
Run Code Online (Sandbox Code Playgroud)

有什么东西我错过了吗?这种行为可能是什么原因?

Boh*_*ian 6

使用流和循环之间存在一个显着差异 - 算术溢出的可能性.

Arrays.stream(int[])返回一个IntStream,其sum()方法返回一个int结果.如果总和超过Integer.MAX_VALUE,则会发生静默整数溢出.

但是,您的循环通过向总计添加int值来求和long,这不会受到算术溢出的影响.

其中一个测试中的整数之和必须超过Integer.MAX_VALUE,测试a long用于(正确)计算总数.


如果要使用流来求和,则需要将其转换IntStream为a LongStream,您可以这样做:

long sum = Arrays.stream(big).asLongStream().sum();
Run Code Online (Sandbox Code Playgroud)

  • @MayurKulkarni如果数组是`long []`,但只存储`int`大小的值,那么你的原始代码`Arrays.stream(arr).sum()`会起作用,因为`Arrays.stream(long [] )`返回一个`LongStream`. (2认同)