![](/img/trans.png)
[英]Why can I not replace BigInteger(“1”) with BigInteger.ONE?
[英]I want to replace BigInteger for loop in Stream Api
想要替換 Java Stream API 中的 BigInteger 循環。
下面的代碼,我必須使用 Stream API 在 java8 中進行修改。 因為性能問題。 我的問題是將以下代碼更改為最佳性能的最佳實踐是什么。
public BigInteger getSum(BigInteger n, BigInteger c) {
BigInteger sum = BigInteger.ZERO;
for (BigInteger i = BigInteger.ZERO; i.compareTo(n) < 0; i=i.add(BigInteger.ONE)) {
sum = sum.add(calculateProduct(i, i.subtract(BigInteger.ONE), c));
}
return sum;
}
private BigInteger calculateProduct(BigInteger i, BigInteger j, BigInteger c) {
if (j.compareTo(BigInteger.ZERO) < 0) return BigInteger.ZERO;
if (j.compareTo(BigInteger.ZERO) == 0) return BigInteger.ONE;
if ((i.subtract(j).compareTo(c)) <= 0){
return j.add(BigInteger.ONE).multiply(calculateProduct(i, j.subtract(BigInteger.ONE), c));
}else
return BigInteger.ONE;
}
看起來您正在添加寬度為c
的滑動窗口的乘積。 如果您想提高性能,請擺脫遞歸並避免重新計算整個產品。 使用上一步計算的乘積:乘以進入窗口的數字並除以退出窗口的數字。 除法較慢,但它會為c
較大值帶來回報。
最后,雖然我會保留你的方法簽名,但你真的只需要BigInteger
作為回報。
BigInteger getSum(BigInteger n, BigInteger c) {
BigInteger p = BigInteger.ONE, sum = BigInteger.ZERO;
for (BigInteger x = BigInteger.ONE; x.compareTo(n) < 0; x = x.add(BigInteger.ONE)) {
p = p.multiply(x);
if (x.compareTo(c) > 0) {
p = p.divide(x.subtract(c));
}
sum = sum.add(p);
}
return sum;
}
如果你想進一步加快速度,你可以使用一些數學方法來避免每一步都需要除法。 您的總和可以分解為s1 = sum[1,c) x!
和s2 = sum[c,n) x!/(xc)!
. 第二個總和等於n!/(nc-1)!/(c+1)
(來自曲棍球棒標識)。 下面的方法不處理 c >=n 的微不足道的情況。 我會把它留給你。
private static BigInteger fasterSum(BigInteger n, BigInteger c) {
assert c.compareTo(n) < 0;
BigInteger sum = ZERO, p = ONE;
for (BigInteger x = ONE; x.compareTo(c) < 0; x = x.add(ONE)) {
p = p.multiply(x);
sum = sum.add(p);
}
// sum[c,n) x!/(x-c)! = n!/(n-c-1)!/(c+1)
p = ONE;
for (BigInteger x = n.subtract(c); x.compareTo(n) <= 0; x = x.add(ONE)) {
p = p.multiply(x);
}
sum = sum.add(p.divide(c.add(ONE)));
return sum;
}
所以我假設你想添加一個BigInteger
列表:
您可以通過使用減少操作來做到這一點( https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html )
List<BigInteger> list = new ArrayList<>();
list.add(BigInteger.valueOf(5));
list.add(BigInteger.valueOf(1));
list.add(BigInteger.valueOf(3));
list.add(BigInteger.valueOf(10));
list.add(BigInteger.valueOf(2));
BigInteger sum = list.stream().reduce((x, y) -> x.add(y)).get();
System.out.println(sum);
這將計算總和,等價的將是:
BigInteger sum = list.stream().reduce(BigInteger::add).get();
您還可以編寫一個自己的可重用的Collector
並將減少操作提取到那里:
public static Collector<BigInteger, ?, BigInteger> calculateSum() {
return Collectors.reducing(BigInteger.ZERO, BigInteger::add);
}
然后做:
BigInteger sum = list.stream().collect(calculateSum());
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.