我的目标是在Java中删除数组中的所有负数。
我已经写了下面的代码。我如何提高代码的复杂性,或者有一个好的算法?
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) {
List<Integer> list = new ArrayList<>();
for (int n : num) {
if (n >= 0) {
list.add(n);
}
}
int[] result = new int[list.size()];
for (int i = 0; i < result.length; i++) {
result[i] = list.get(i).intValue();
}
return result;
}
发布于 2016-11-07 03:49:38
Java 8 streams怎么样?
Arrays.stream(num).filter(s -> s >= 0).toArray();
发布于 2016-11-07 07:10:13
我认为在效率方面,我们不能比@kaidul伊斯拉姆答案(和@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伊斯拉姆方法与我的方法是多么接近。
更新:这里是jmh benchmark I wrote的链接,这样你可以验证更真实的场景(如果有人发现我如何设置测试的问题,请让我知道)。在我对另一个答案的测试中,有一个对Trove的依赖性。
发布于 2016-11-07 01:35:31
这将通过一次迭代就地完成:
保存两个索引:原始数组上的src
和dst
。两者都被初始化为0。
当数字为正数时,将其从num[src]
复制到num[dst]
,并使两个索引都前进
当数字为负数时,只需前进src
。
返回新大小为dst
的原始数组。
public static int removeNegativeNumbers(int[] num) {
int dst=0;
for (int src=0 ; src<num.length ; ++src)
if (num[src]>=0)
num[dst++] = num[src];
return dst;
}
https://stackoverflow.com/questions/40452330
复制相似问题