我认为在效率方面,我们无法比@kaidul-islam的答案(以及@user6904265的简洁性)更好。
我只是添加了一个解决方案,在非常特定的场景中应该有一定的价值,其中负数很少出现且数组非常大。
基本思想是推迟实际复制,直到找到负值,然后使用System.arraycopy进行复制。如果没有找到负值,则返回源数组。
import java.util.*;
public class NotNegativeTest {
public static void main(String[] args) {
int[] array = { 1, -3, 4, -9, 3, 4, 70, -10, 0, 7 };
System.out.println(Arrays.toString(removeNegativeNumbers(array)));
}
public static int[] removeNegativeNumbers(int[] num) {
int[] output = new int[num.length];
int k = 0;
int i = 0;
int last=-1;
int howmany=0;
while(i < num.length) {
if(num[i] < 0) {
howmany=i-last-1;
switch(howmany) {
case 0: break;
case 1:
output[k]=num[last+1];
k++;
break;
default:
System.arraycopy(num, last+1, output, k, howmany);
k+=howmany;
}
last=i;
}
i++;
}
if (last>=0) {
if(last!=i-1) {
howmany=i-last-1;
System.arraycopy(num, last+1, output, k, howmany);
k+=howmany;
}
} else {
return num;
}
return Arrays.copyOfRange(output, 0, k);
}
}
我已经找到时间编写了一个JMH微基准测试。
我使用了以下配置:
Options opts = new OptionsBuilder()
.include(MyBenchmark.class.getSimpleName())
.mode(Mode.AverageTime)
.warmupIterations(1)
.warmupTime(TimeValue.seconds(5))
.measurementIterations(10)
.measurementTime(TimeValue.seconds(5))
.jvmArgs("-server")
.forks(1)
.build();
new Runner(opts).run();
(免责声明:这是我第一次进行JMH测试,如果有人有建议,我很乐意更改并更新结果)
以下是测试结果:
# Run complete. Total time: 00:02:54
Benchmark Mode Cnt Score Error Units
MyBenchmark.testMethodUser6904265 avgt 10 0,201 ± 0,040 s/op
MyBenchmark.testMethodInsac avgt 10 0,093 ± 0,022 s/op
MyBenchmark.testMethodKaidul avgt 10 0,124 ± 0,029 s/op
现在,在为我欢呼之前,请看一下测试有多么偏颇:
int[] array = new int[10000000];
array[0]=-5;
array[10000]=-3;
array[40000]=-3;
array[8000000]=-3;
int[] answer=NotNegativeTest.removeNegativeNumbers(array);
所以需要注意的是,我的方法并不是赢了(测试是为了让我的方法赢得胜利:-),而是即使在这种极端情况下,通用的kaidul-islam方法与我的方法非常接近。
更新:这里是我编写的jmh基准测试链接,您可以验证更现实的情况(如果有人发现我设置测试的问题,请告诉我)。还有一个依赖于Trove的测试,我在另一个答案中做了说明。
int[]
、long[]
、double[]
和任何Object[]
,但不适用于byte[]
、short[]
、char[]
或float[]
,因为这些类型没有Arrays.stream
方法。 - Boann