【问题标题】:generating all unique pairs from a list of numbers, n choose 2从数字列表中生成所有唯一对,n 选择 2
【发布时间】:2012-02-26 12:29:49
【问题描述】:

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

【问题讨论】:

    标签: java algorithm math combinations combinatorics


    【解决方案1】:

    嗯,你不能,对吧?

    结果是一个包含n*(n-1)/2 元素的列表,无论这些元素是什么,只要填充这个列表(比如用零)就需要O(n^2) 时间,因为n*(n-1)/2 = O(n^2)...

    【讨论】:

    • 如果我能找到避免内循环的方法,这至少在理论上会使其更快吗?我试图用一个循环(while循环)出来,事实上,这需要更长的时间。我会发布代码。
    • 顺便说一句,最坏情况下的运行时间复杂度不是由算法和输入的实际步骤定义的,而不是输出吗?
    • 其实……不!你有多少个内循环并不重要。重要的是迭代次数。即使你用一个循环编写它,这个循环也必须有n*(n-1)/2 迭代,所以它的复杂性是一样的。
    【解决方案2】:

    您不能将其设为次二次曲线,因为正如您所说 - 输出本身就是二次曲线 - 要创建它,您至少需要 #elements_in_output ops。

    但是,您可以做一些“作弊”即时创建您的列表
    您可以创建一个实现Iterable&lt;Pair&gt; 的类CombinationsGetter,并实现它的Iterator&lt;Pair&gt;。这样,您将能够动态地迭代元素,而无需先创建列表,这可能会减少您的应用程序的延迟。

    注意:它仍然是二次的!动态生成列表的时间将分配给更多操作。


    编辑: 另一种比简单方法更快的解决方案是多线程
    创建几个线程,每个线程都将获取他的数据“切片” - 并生成相关对,并创建自己的部分列表。
    稍后 - 您可以使用 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 对象。

    【讨论】:

    • 我已经发布了一个不同的版本来获得这对。它只有 1 个循环。你能帮忙回答我上面的问题吗?这是第二个算法 O(n) 吗?我同意您的建议(动态创建和多线程)。动态创建不会太难实现,但多线程可能会更快,但代价是不那么优雅的代码/编码。如果我开始传递巨大的 List> (我正在考虑这样做),它甚至可能会更慢。
    • @JaneWayne:你不能比O(n^2)更好地创建所有需要的对。我编辑了答案以对您的第二次实施进行具体分析,但无论您做什么 - 创建 O(n^2) Pair 对象,都需要 O(n^2) 操作。
    • 谢谢。我一直在努力获得一本关于算法分析的好书(不是大多数大学使用的那种大的精装书)。如果您有任何建议,请告诉我。
    猜你喜欢
    • 1970-01-01
    • 2019-03-26
    • 2019-09-07
    • 1970-01-01
    • 2012-03-14
    • 1970-01-01
    • 1970-01-01
    • 2022-01-26
    • 1970-01-01
    相关资源
    最近更新 更多