对于下面的问题,Java8提供了更好的选项。
有两个数组,一个整数数组和一个增量数组。将每个增量值应用于整数数组中的元素,然后将每个增量相加,得到增量元素的绝对值之和。
import java.util.Arrays;
public class ArrayChallenge {
public static void main(String[] args) {
long[] nA = {-3, -2, 4, 5};
long[] iA = {2, 4, -6};
long[] sumArr = findAbsValueSum(nA, iA);
System.out.println(Arrays.toString(sumArr));
}
public static long[] findAbsValueSum(long[] numArr, long[] incrArr) {
long[] sumArr = new long[incrArr.length];
for (int i = 0; i < incrArr.length; i++) {
long sum = 0;
for (int j = 0; j < numArr.length; j++) {
sum = sum + Math.abs(numArr[j] + incrArr[i]);
numArr[j] = numArr[j] + incrArr[i];
}
sumArr[i] = sum;
}
return sumArr;
}
}
Result:
[14, 28, 14]
在Java8中有没有更好的选项(性能方面)来实现同样的功能?
3条答案
按热度按时间fruv7luv1#
你粘贴的代码显然是高效的,因为它将得到。电脑不是魔法;如果你发现其他语言或图书馆
sumAll
功能,它只是在引擎盖下做这个。如果你想它更有效,你需要设置规则。限制输入或扩大允许做的事情,这样你可以让这更有效。
例如,如果你告诉我
numArr
是众所周知的提前,因此任何工作所做的转变numArr
对于不同的、更有效的(对于这个特定的任务)数据类型是“免费的”,因为唯一相关的事情就是尽可能快地一次返回答案incrArr
如果可用,则:排序
numArr
到位(免费-可以做不知道incrarr)。构建增量和数组。此数组是此索引处所有数字的绝对值+以前所有索引的总和;
{-3, -2, 4, 5}
变成{0, 3, 5, 9, 14}
. (免费-可以在不知道incrarr的情况下完成)计算正增量的SUMAB
对于这个例子,假设你的增量(
I
)是2
.首先,对
-I
发生;我们称之为IDX(-I)
. 在这里,IDX(-2)
=1(因为numArr[1]
是-2
). 如果-I
不在列表中,是最近的较小数字(如果列表中没有-2,请查找-3)(成本:o(logn))。对于这个数字,以及所有的数字
numArr
在这个指数之下,答案是微不足道的:它是所有这些数字的绝对值之和,减去xi。这是O(1)
:这很简单sumArr[IDX(-I)] - (IDX(-I) * I)
.接下来找到索引0(cost:o(logn))。对于所有0以上的数字,答案同样微不足道。我们首先需要所有正数的和,也就是
sumArr[sumArr.length - 1] - sumArr[idx(0)]
,然后为其中的每个数字加上xi,类似于我们处理负数的方式。这就把有趣的部分放在了中间,比如
-1
-它只起作用1
总计(-1+2=+1)。没有快速的解决方法,因此仅对于输入的这一部分,我们必须遍历它(因此从IDX(-I)
至IDX(0)
排他性,做数学。这在技术上是o(n),除了n是严格限制的;永远不会超过I
除非列表中有重复项(如果有,也可以通过在自由预计算阶段创建权重数组来批量处理这些重复项),而且通常要少得多;它是重叠:输入中所有介于0和-i之间的值。增量为负
同样的算法也适用,但相反:对于诸如
-6
,0或以下的所有数字都是微不足道的,6或更高的所有数字也是微不足道的。循环只需要覆盖1到5之间的所有数字。这会产生一个o(logn)+o(restricted-n)的算法,而不是现有的o(n)算法。在纯数学术语中,它仍然是o(n),但在几乎所有的场景中,它的运算量都要少几个数量级。
构建求和表本身就是o(n),所以如果preptime不是“免费的”,那么这些都没有意义,而且您所描述的是它将获得的最快速度。
nnvyjq4y2#
代替(原始代码段)
第一个微优化(切换两行以删除第二行的总和):
以及更多的微观优化(使用复合赋值)
更微观的优化(使用变量而不是数组访问)
但是最终jit编译器已经在这样做了(对于更大的数组)。
无法知道这是否真的有帮助,或者差异是否敏感,因为这是微观优化,没有进行测试/计时
7kjnsjlb3#
“流”版本可能如下所示:
更新
可以使用较短的形式:
羔羊
(i -> {long abs = Math.abs(numArr[i] + inc); numArr[i] += inc; return abs;})
可替换为等效的(i -> Math.abs(numArr[i] += inc))
它为给定的测试数据提供相同的输出:输出:
但是,流解决方案的性能看起来并不高,因为它使用了类似的嵌套循环。
此外,这里根本不应该使用流,因为其中一个输入数组
numArr
在处理流时被修改,因此它有副作用,不能并行运行以提高性能,因为结果不正确。