提问人:Jahnavi Achanta 提问时间:9/30/2023 最后编辑:Mark RotteveelJahnavi Achanta 更新时间:10/4/2023 访问量:79
如何通过排除列表中的一个元素来计算元素的最小值和最大值时防止溢出
How to prevent overflow when calculating min & max sum of the elements by excluding one element in the list
问:
我需要找到可以通过精确求和(大小 - 1)数组中的元素来计算的最小值和最大值
示例:
arr = [1,2,3,4,5] minSum = 1+2+3+4 = 10 , maxSum = 2+3+4+5 = 14
最初,我编写了以下代码
public static void miniMaxSum(List<Integer> arr) {
List<Integer> sorted = arr.stream().sorted().collect(Collectors.toList());
Integer totalSum = sorted.stream().mapToInt(Integer::intValue).sum();
Integer minSum = totalSum - sorted.get(sorted.size()-1);
Integer maxSum = totalSum - sorted.get(0);
System.out.println(minSum + " "+maxSum);
}
对于简单的测试用例,它按预期工作,但对于具有较高值的数字,它会溢出并导致负值,因此我使用了 BigInteger。
public static void miniMaxSum(List<Integer> arr) {
List<Integer> sorted = arr.stream().sorted().collect(Collectors.toList());
BigInteger totalSum = BigInteger.valueOf(sorted.stream().mapToInt(Integer::intValue).sum());
BigInteger minSum = totalSum.subtract(BigInteger.valueOf(sorted.get(sorted.size()-1)));
BigInteger maxSum = totalSum.subtract(BigInteger.valueOf(sorted.get(0)));
System.out.println(minSum + " "+maxSum);
}
即便如此,它也会导致负值
输入 : 793810624 895642170 685903712 623789054 468592370
输出 : -1722871536 -1295821736
为什么即使在使用 BigInteger 后也会导致负值,应该如何处理?
答:
问题在于,当你创建时,溢出已经发生了,因为你把整数相加为 ,这意味着结果也是一个 .只有这样,您的代码才会将此溢出结果转换为 .totalSum
int
int
BigInteger
相反,您需要使用以下命令进行计算:BigInteger
BigInteger totalSum = sorted.stream()
.reduce(BigInteger.ZERO,
(sum, value) -> sum.add(BigInteger.valueOf(value)),
BigInteger::add);
这相当于做:
BigInteger totalSum = sorted.stream()
.map(v -> BigInteger.valueOf(v.longValue()))
.reduce(BigInteger.ZERO, BigInteger::add);
"...为什么即使在使用 BigInteger 后也会导致负值,应该如何处理?..."
利用 map 方法将流解析为 BigInteger 值。
并且,reduce方法对元素进行总计。
List<Integer> sorted = new ArrayList<>(arr);
Collections.sort(sorted);
BigInteger min
= sorted.stream()
.limit(sorted.size() - 1)
.map(x -> new BigInteger(String.valueOf(x)))
.reduce(BigInteger::add)
.get();
BigInteger max
= sorted.stream()
.skip(1)
.map(x -> new BigInteger(String.valueOf(x)))
.reduce(BigInteger::add)
.get();
System.out.println(min + " "+max);
输出
10 14
正如其他人所说,将值转换为数据丢失发生后,并不能解决您的问题。操作本身必须使用比 更大的数据类型来执行。BigInteger
int
但是对列表进行排序,只是为了获得最小值和最大值,也是非常低效的。有一个内置操作,可以一次执行所有必要的操作,获取最小值、最大值和总和。它用于求和,这足以处理所有不能超过 2³¹ 元素的普通集合。summaryStatistics()
long
public static void miniMaxSum(List<Integer> arr) {
IntSummaryStatistics s = arr.stream()
.mapToInt(Integer::intValue).summaryStatistics();
long totalSum = s.getSum();
long minSum = totalSum - s.getMax();
long maxSum = totalSum - s.getMin();
System.out.println(minSum + " " + maxSum);
}
进一步注意,这里没有理由使用盒装或对象。Integer
Long
评论
BigInteger
int
Integer
BigInteger
long
Long
BigInteger