Search code examples
javalistjava-streaminteger-overflow

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

Solution

  • 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