我有一个元素列表(比如整数),我需要进行所有可能的2对比较。我的方法是O(n ^ 2),我想知道是否有更快的方法。这是我在java中的实现。
public class Pair {
public int x, y;
public Pair(int x, int y) {
this.x = x;
this.y = y;
}
}
public List<Pair> getAllPairs(List<Integer> numbers) {
List<Pair> pairs = new ArrayList<Pair>();
int total = numbers.size();
for(int i=0; i < total; i++) {
int num1 = numbers.get(i).intValue();
for(int j=i+1; j < total; j++) {
int num2 = numbers.get(j).intValue();
pairs.add(new Pair(num1,num2));
}
}
return pairs;
}
请注意我不允许自配,所以应该有((n(n + 1))/ 2) - n个可能的对。我目前的工作原理,但随着n的增加,我需要花费大量的时间才能获得成对。有没有办法将上面的O(n ^ 2)算法转换为亚二次方?任何帮助表示赞赏。
顺便说一下,我也试过下面的算法,但是当我基准测试时,根据经验,它的性能比我上面的要差。我以为通过避免内循环,这会加快速度。下面这个算法不应该更快吗?我会认为它是O(n)?如果没有,请解释并告诉我。感谢。public List<Pair> getAllPairs(List<Integer> numbers) {
int n = list.size();
int i = 0;
int j = i + 1;
while(true) {
int num1 = list.get(i);
int num2 = list.get(j);
pairs.add(new Pair(num1,num2));
j++;
if(j >= n) {
i++;
j = i + 1;
}
if(i >= n - 1) {
break;
}
}
}
答案 0 :(得分:6)
嗯,你不能,对吧?
结果是一个包含n*(n-1)/2
元素的列表,无论这些元素是什么,只需填充此列表(比如用零填充)需要O(n^2)
时间,因为n*(n-1)/2 = O(n^2)
...
答案 1 :(得分:4)
你不能使它成为次二次曲面,因为如你所说 - 输出本身是二次曲线 - 并且要创建它,你至少需要#elements_in_output
个操作。
但是,您可以做一些“作弊”动态创建列表:
您可以创建一个实现Iterable<Pair>
的类CombinationsGetter
,并实现其Iterator<Pair>
。这样,您就可以动态迭代这些元素,而无需先创建列表,这可能会减少应用程序的延迟。
注意:它仍然是二次曲线!动态生成列表的时间将在更多操作之间分配。
修改强>
另一种解决方案,比简单的方法更快 - 是多线程。
创建几个线程,每个线程将获得数据的“切片” - 并生成相关对,并创建自己的部分列表。
稍后 - 您可以使用ArrayList.addAll()
将这些不同的列表转换为一个。
注意:虽然复杂度很高O(n^2)
,但它可能要快得多 - 因为对的创建是并行完成的,并且ArrayList.addAll()
实现的很多更有效率,然后逐个插入一个元素。
<强> EDIT2:强>
您的第二个代码仍为O(n^2)
,即使它是“单循环” - 循环本身将重复O(n^2)
次。看看变量i
。它仅在j==n
时增加,并在j
执行时减少i+1
。因此,它会导致n + (n-1) + ... + 1
次迭代,这是sum of arithmetic progression,并按预期将我们带回O(n^2)
。
我们不能比O(n ^ 2)好,因为我们正在尝试创建O(n ^ 2)个不同的Pair
个对象。