简体   繁体   English

使用 Java 8 流从整数列表中计算最小和最大和

[英]Calculating Min and Max sums from a List of Integer using Java 8 streams

I am trying to solve the following challenge:我正在尝试解决以下挑战:

Given five positive integers, find the minimum and maximum values that can be calculated by summing exactly four of the five integers.给定五个正整数,找出可以通过将五个整数中的四个恰好相加来计算的最小值和最大值。 Then print the respective minimum and maximum values as a single line of two space-separated long integers.然后将各自的最小值最大值打印为单行的两个空格分隔long整数。

My code which can be seen below is able to handle some test cases but fails others which I cannot seem to figure out, the issue seems to lie with the long max assignment statement, and probably with the .sorted(Collections.reverseOrder()) component as that is the only tangible difference between the min vs max statements.下面可以看到我的代码能够处理一些测试用例,但其他一些我似乎无法弄清楚的失败,问题似乎在于long max赋值语句,并且可能与.sorted(Collections.reverseOrder())组件,因为这是 min 与 max 语句之间的唯一明显区别。

Example test case where it works:有效的示例测试用例:

Input = [1, 2, 3, 4, 5]

Output = 10 (minimum), 14 (maximum)

Example test case where it does not work:不起作用的示例测试用例:

Input = [256741038, 623958417, 
   467905213, 714532089, 938071625]

Output = 2063136757 (minimum), 
  -1550499952 (maximum)

Expected Output = 2063136757 
  (minimum), 2744467344 (maximum)

My code:我的代码:

class Result {
    
    /*
     * Complete the 'miniMaxSum' function below.
     *
     * The function accepts. INTEGER_ARRAY arr as parameter.
     */
    
    public static void miniMaxSum(List<Integer> arr) {
        long max = arr.stream().sorted(Collections.reverseOrder())
                .limit(4)
                .reduce(0, (subtotal, element) -> subtotal + element);
        long min = arr.stream().sorted().limit(4).reduce(0,
                (subtotal, element) -> subtotal + element);
        System.out.println(min + " " + max);
    }
}

public class Solution {
    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader =
                new BufferedReader(new InputStreamReader(System.in));
        
        List<Integer> arr = Stream
                .of(bufferedReader.readLine().replaceAll("\\s+$", "")
                        .split(" "))
                .map(Integer::parseInt).collect(toList());
        
        Result.miniMaxSum(arr);
        
        bufferedReader.close();
    }
}

As @Benjamin W. has said, there seems to be some overflowing occurring here.正如@Benjamin W. 所说,这里似乎发生了一些溢出。 It might have to do with the list containing Integer objects instead of longs, but you would have to look into it further.它可能与包含 Integer 对象而不是 long 的列表有关,但您必须进一步研究它。 Your buffered reader seams like it is working perfectly fine.你的缓冲阅读器看起来工作得很好。

If you just want a simple solution, you could just find the smallest number in the list, and omit it from the largest sum, and find the largest element from the list, and omit it from the smallest sum.如果你只是想要一个简单的解决方案,你可以在列表中找到最小的数字,从最大的和中省略它,从列表中找到最大的元素,从最小的和中省略它。

public static void minmaxSum(List<Integer> arr) {
    if (arr.size() == 0) return;

    long max = arr.get(0):
    long min = arr.get(0);

    long maxSum = 0;
    long minSum = 0;

    for (Integer num : arr) {
        long longNum = (long) num.intValue();
        
        maxSum += longNum;
        minSum += longNum;

        if (longNum < min) min = longNum;
        if (longNum > max) max = longNum;
    }

    maxSum -= min;
    minSum -= max;

    System.out.println(minSum + " " + maxSum);
}       

Besides, code like this is much more clear anyway.此外,这样的代码无论如何都要清晰得多。

Math.addExact

As explained in the Answer by ShinyMustard22 , you seem to be encountering problems with overflowing the limits of your integer type.正如ShinyMustard22 的答案中所解释的,您似乎遇到了溢出整数类型限制的问题。

An overflow occurs with no warning to you.发生溢出而没有警告您。 If you want to be informed when an overflow occurs, and you should want that, use the …Exact methods found on the Math class.如果您想在发生溢出时得到通知,并且您应该希望这样做,请使用Math类中的…Exact方法。 If an overflow occurs during the operation, an exception is thrown.如果在操作过程中发生溢出,则抛出异常。 You trap for that exception to resolve the situation in a manner of your choosing.您捕获该异常,以您选择的方式解决情况。

For example, Math.addExact( long x , long y ) .例如, Math.addExact( long x , long y )

The overflow occurs because you are performing reduction on a stream of Integer , ie accumulator of the reduce() operation deals with Interger objects, and then you're assigning the overflown result of the calculation to a variable of type long .发生溢出是因为您正在对Integer流执行归约,即reduce()操作的累加器处理Interger对象,然后将计算的溢出结果分配给long类型的变量。

LongSummaryStatistics & LongStream LongSummaryStatistics & LongStream

Since only one value should be discarded in both cases ( for min and max sum ), we can approach this problem by calculating the total of all elements and subtracting the value of the lowest element to obtain the maximum sum and subtracting the value of the highest element to get the minimum sum .由于在两种情况下都应该丢弃一个值(对于minmax sum ),我们可以通过计算所有元素的总和并减去最低元素的值以获得最大和并减去最高元素的值来解决这个问题元素来获得最小总和

There's no need to apply sorting and hard-code the value of 4 in the stream.无需在流中应用排序和硬编码4的值。 If you don't want to develop bad habits, try to design your solutions to be clean and generalized.如果您不想养成坏习惯,请尝试将您的解决方案设计为干净且通用的。

We can get all three values ( total , the lowest element , the highest element ) by performing a single iteration over the given list.我们可以通过对给定列表执行单次迭代来获得所有三个值(总计最低元素最高元素)。 It can be done "manually" by tracking these values while iterating with a for loop, or we can make use of one of the summary statistics classes from the JDK to get this job done for us.它可以通过在使用for循环迭代时跟踪这些值来“手动”完成,或者我们可以使用 JDK 中的一个汇总统计类来为我们完成这项工作。

From the summary statistics object we can extract information about the total sum, minimum and maximum values, using its methods getSum() , getMin() and getMax() .汇总统计对象中,我们可以使用其方法getSum() 、 getMin() 和getMax()提取有关总和、最小值和最大值的信息。 To avoid int overflow we have to use LongSummaryStatistics .为了避免int溢出,我们必须使用LongSummaryStatistics And we can obtain this object from a LongStream by applying summaryStatistics() as a terminal operation.我们可以通过将summaryStatistics()作为终端操作从LongStream中获取该对象。

public static void miniMaxSum(List<Integer> arr) {
    LongSummaryStatistics statistics = arr.stream()
        .mapToLong(i -> i)
        .summaryStatistics();
    
    long max = statistics.getSum() - statistics.getMin();
    long min = statistics.getSum() - statistics.getMax();
    
    System.out.println(min + " " + max);
}

main()

public static void main(String[] args) {
    miniMaxSum(List.of(256741038, 623958417, 467905213, 714532089, 938071625));
}

Output:输出:

2063136757 2744467344

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM