从数字列表中生成所有唯一对,n选择2

时间:2012-02-26 12:29:50

标签: java algorithm math combinations combinatorics

我有一个元素列表(比如整数),我需要进行所有可能的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;
  }
 }
}

2 个答案:

答案 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个对象。