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();
}
}
CodePudding user response:
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.
CodePudding user response:
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 )
.
CodePudding user response:
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