Nasri
Nasri

Reputation: 15

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.

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.

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();
    }
}

Upvotes: 1

Views: 1601

Answers (4)

Ravi S
Ravi S

Reputation: 1

Its much easier with plain arrays.sort. here is my code

package com.comm.examples;
/*
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.
 */
import java.util.*;

public class MaxAndMinSumsInArray {
    public static void main(String[] args) {
        int[] inpa  = {256741038, 623958417,
                467905213, 714532089, 938071625};
        Arrays.sort(inpa);
        long max = 0, min = 0;
        for (int i = inpa.length -4; i < inpa.length; i++) max += inpa[i];
        for (int i = 0; i < 4; i++) min += inpa[i];

        System.out.println("Max=" + max + " min=" + min);
    }
}

Output: Max=2744467344 min=2063136757

Upvotes: 0

ShinyMustard22
ShinyMustard22

Reputation: 66

As @Benjamin W. has said, there seems to be some overflowing occurring here. It might have to do with the list containing Integer objects instead of longs, but you would have to look into it further. 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.

Upvotes: 3

Alexander Ivanchenko
Alexander Ivanchenko

Reputation: 28978

The overflow occurs because you are performing reduction on a stream of Integer, i.e. 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.

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.

There's no need to apply sorting and hard-code the value of 4 in the stream. 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.

From the summary statistics object we can extract information about the total sum, minimum and maximum values, using its methods getSum(), getMin() and getMax(). To avoid int overflow we have to use LongSummaryStatistics. And we can obtain this object from a LongStream by applying summaryStatistics() as a terminal operation.

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

Upvotes: 1

Basil Bourque
Basil Bourque

Reputation: 338416

Math.addExact

As explained in the Answer by ShinyMustard22, you seem to be encountering problems with overflowing the limits of your integer type.

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. 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 ).

Upvotes: 0

Related Questions