[英]Working with Arrays Java - Any better options available
Any better options available in java 8 for the below problem. java 8 中针对以下问题提供的任何更好的选项。
There are two arrays, one integral array and one incremental array.Apply each of the increment values to the elements in integral array and get the sum of absolute values of the elements of incremental after adding each increment.有两个arrays,一个整数数组和一个增量数组。将每个增量值应用到整数数组中的元素,得到每个增量后增量元素的绝对值之和。
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]
Is there any better options (Performance wise) to do the same in java 8?在 java 8 中是否有更好的选择(性能方面)?
The code you pasted is obviously as efficient as it is going to get.您粘贴的代码显然与将要获得的一样有效。 Computers aren't magic;
计算机不是魔法。 if you find some other language or library that has a
sumAll
function, it'd just be doing this under the hood.如果您发现其他一些语言或库具有
sumAll
function,那么它只是在后台执行此操作。
If you want it to be more efficient, you need to setup rules.如果你想让它更有效率,你需要设置规则。 Restrict the input or widen the things one is allowed to do, then you can get this to be more efficient.
限制输入或扩大允许做的事情,然后你可以让它更有效率。
For example, if you tell me that numArr
is known well in advance and therefore any work done to transform numArr
into different, more efficient (for this specific task) data types is 'free', because the only thing that is relevant is to return the answer as fast as possible once an incrArr
is available, then:例如,如果您告诉我
numArr
是事先众所周知的,因此任何将numArr
转换为不同的、更有效(对于此特定任务)数据类型的工作都是“免费的”,因为唯一相关的是返回一旦incrArr
可用,就尽快回答,然后:
numArr
in place.numArr
进行就地排序。 (free - can be done without knowing incrArr). {-3, -2, 4, 5}
turns into {0, 3, 5, 9, 14}
. {-3, -2, 4, 5}
变成{0, 3, 5, 9, 14}
。 (free - can be done without knowing incrArr) For this example, let's say your increment ( I
) is 2
.对于此示例,假设您的增量 (
I
) 为2
。
-I
occurs;-I
的索引进行二分查找; we shall call this IDX(-I)
.IDX(-I)
。 Here, IDX(-2)
= 1 (because numArr[1]
is -2
).IDX(-2)
= 1 (因为numArr[1]
是-2
)。 If -I
isn't in the list, the nearest smaller number (Had -2 not been in your list, find -3 instead).-I
不在列表中,则为最接近的较小数字(如果 -2 不在您的列表中,则改为查找 -3)。 (cost: O(logn)). numArr
below this index, the answer is trivial: It is the sum of the absolute value of all those numbers, minus X*I.numArr
中低于该索引的所有数字,答案很简单:它是所有这些数字的绝对值之和,减去 X*I。 This is O(1)
: it is simply sumArr[IDX(-I)] - (IDX(-I) * I)
.O(1)
:它只是sumArr[IDX(-I)] - (IDX(-I) * I)
。sumArr[sumArr.length - 1] - sumArr[idx(0)]
, then add X*I to this for each number in it, analogous to how we handled the negative numbers.sumArr[sumArr.length - 1] - sumArr[idx(0)]
,然后为其中的每个数字添加 X*I,类似于我们处理负数的方式.-1
- which contributes only 1
to the sum total (-1 + 2 = +1).-1
- 它仅对总和贡献1
(-1 + 2 = +1)。 There is no speedy way out, so for only this slice of the input, we must iterate through it(so from IDX(-I)
to IDX(0)
exclusive, doing the math. This is technically O(n), except n is heavily limited; it can never be more than I
unless there are duplicates in your list (and if there are, there are ways to handle those in bulk as well by making a weight array in the free precalculation phase), and is usually much less; it is the overlap: All values in the input which are between 0 and -I.IDX(-I)
到IDX(0)
独占,做数学。这在技术上是 O(n),除了 n受到很大限制;除非您的列表中有重复项,否则它永远不会超过I
(如果有,也可以通过在免费的预计算阶段制作一个权重数组来批量处理这些重复项),并且通常很多少;这是重叠:输入中的所有值都在 0 和 -I 之间。The exact same algorithm applies, but reversed: For an increment such as -6
, all numbers at 0 or below are trivial, as are all numbers at 6 or higher.完全相同的算法适用,但相反:对于诸如
-6
之类的增量,0 或以下的所有数字都是微不足道的,6 或更高的所有数字也是如此。 The loop needs to only cover all numbers between 1 and 5, inclusive.循环只需要覆盖 1 到 5 之间的所有数字,包括 1 和 5。
This results in an algorithm that is O(logn) +O(restricted-n) instead of the O(n) algorithm you have.这导致算法为 O(logn) +O(restricted-n) 而不是您拥有的 O(n) 算法。 In purely mathematical terms, it's still O(n), but in almost all scenarios it's orders of magnitude fewer operations.
用纯粹的数学术语来说,它仍然是 O(n),但在几乎所有情况下,它的运算量都少了几个数量级。
Building the sum tables is itself O(n), so if the preptime is not 'free', there is no point to any of this, and what you described is as fast as it is going to get.构建总和表本身就是 O(n),所以如果准备时间不是“免费的”,那么这一切都没有意义,而且你所描述的速度将达到最快。
The "stream" version may look like this: “流”版本可能如下所示:
public static long[] findAbsValueSumStream(long[] numArr, long[] incrArr) {
return Arrays.stream(incrArr)
.map(inc -> IntStream.range(0, numArr.length)
.mapToLong(i -> Math.abs(numArr[i] += inc))
.sum()
)
.toArray();
}
Update更新
Shorter form can be used:可以使用更短的形式:
a lambda (i -> {long abs = Math.abs(numArr[i] + inc); numArr[i] += inc; return abs;})
一个 lambda
(i -> {long abs = Math.abs(numArr[i] + inc); numArr[i] += inc; return abs;})
may be replaced with equivalent (i -> Math.abs(numArr[i] += inc))
可以替换为等效的
(i -> Math.abs(numArr[i] += inc))
It provides the same output for the given test data:它为给定的测试数据提供了相同的 output:
long[] nA = {-3, -2, 4, 5};
long[] iA = {2, 4, -6};
long[] sumArr = findAbsValueSum(nA, iA);
System.out.println("loop: " + Arrays.toString(sumArr));
long[] sumArrStream = findAbsValueSumStream(nA, iA);
System.out.println("stream: " + Arrays.toString(sumArrStream));
Output: Output:
loop: [14, 28, 14]
stream: [14, 28, 14]
However, the stream solution does not look as more performant because it uses similar nested loop.但是,stream 解决方案看起来并没有更高的性能,因为它使用了类似的嵌套循环。
Moreover, stream should not be used here at all because one of the input arrays numArr
is modified while processing the stream, so it has side effects and cannot be run in parallel to increase performance because the results would be incorrect.此外,这里根本不应该使用 stream,因为输入 arrays
numArr
之一在处理 stream 时被修改,所以它有副作用,因为并行运行不会提高性能。
instead of (original code segment)而不是(原始代码段)
sum = sum + Math.abs(numArr[j] + incrArr[i]);
numArr[j] = numArr[j] + incrArr[i];
first micro-optimization ( switched the 2 lines to remove the sum from second one):第一次微优化(切换两行以从第二行中删除总和):
numArr[j] = numArr[j] + incrArr[i];
sum = sum + Math.abs(numArr[j]);
and more micro-optimization (using compound assignment)和更多的微优化(使用复合赋值)
numArr[j] += incrArr[i];
sum = sum + Math.abs(numArr[j]);
and even more micro-optimization (using variable instead of array access)甚至更多的微优化(使用变量而不是数组访问)
var n = numArr[j] += incrArr[i];
sum = sum + Math.abs(n);
but eventually the JIT-compiler is already doing that (for bigger arrays).但最终 JIT 编译器已经在这样做了(对于更大的数组)。
unable to know if that really helps or if the difference is sensitive at all since this is micro-optimization and no testing/timing was done无法知道这是否真的有帮助,或者差异是否敏感,因为这是微优化并且没有进行测试/计时
Please find the efficient way to find answer to the above problem请找到找到上述问题答案的有效方法
import java.util.Arrays;
public class BenchMarkedSolution {
public static long[] findAbsValueSum(long[] numArr, long[] incrArr) {
int n = numArr.length;
Arrays.sort(numArr);
long[] res = new long[incrArr.length];
long[] cumArr = new long[n];
long sum = 0, cumIncr = 0;
for (int i = 0; i < n; ++i) {
sum += numArr[i];
cumArr[i] = sum;
}
for (int i = 0; i < incrArr.length; ++i) {
cumIncr += incrArr[i];
int p = Arrays.binarySearch(numArr, -cumIncr);
p = p < 0 ? Math.max(-p - 2, 0) : p;
res[i] = Math.abs(cumArr[p] + cumIncr * (p + 1)) + Math.abs((cumArr[n - 1] - cumArr[p]) + cumIncr * (n - p - 1));
}
return res;
}
public static void main(String[] args) {
long[] numArr;
long[] incArr;
long[] sumArr;
numArr = new long[]{-3, -2, 4, 5};
incArr = new long[]{2, 4, -6};
sumArr = findAbsValueSum(numArr, incArr);
System.out.println(Arrays.toString(sumArr));
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.