【问题标题】:Iterating over all subsets of a given size迭代给定大小的所有子集
【发布时间】:2013-04-10 17:12:19
【问题描述】:

我知道迭代一组大小为 n 的所有子集是一场性能噩梦,需要 O(2^n) 时间。

如何迭代所有大小为 k 的子集(对于 (0

就 n 和 k 而言,最差情况下的性能是多少?除了O(n!/ k!(n - k)!)之外,还有更简单的说法吗?这是渐近小于 O(n!) 还是一样?

【问题讨论】:

  • 显然,这取决于nk 的值。你在寻找什么样的答案?

标签: performance combinatorics


【解决方案1】:

你想要 Gosper 的破解:

int c = (1<<k)-1;
while (c < (1<<n)) {
  dostuff(c);
  int a = c&-c, b = c+a;
  c = (c^b)/4/a|b;
}

解释:

找到设置了尽可能多的位的下一个数字基本上可以简化为只有一个“1 块”的数字的情况 --- 数字有一堆零,然后是一堆一,然后又是一堆零他们的二进制扩展。

处理这样一个“1 块”数字的方法是将最高位向左移动一位,并将所有其他位尽可能低。 Gosper 的破解方法是找到最低设置位 (a),找到包含我们不接触的位和“进位位”(b) 的“高位”,然后生成一组适当的位从最低有效位开始的大小。

【讨论】:

    【解决方案2】:

    很容易证明,对于固定的n(n, k) 的最大值为k = n/2。如果我没有误用 Sterling 的近似值,(n, n/2) 的渐近行为是指数的。

    对于常量k(n, k)O(n^k)。请记住,组合函数是对称的,因此(n, n-k) 也是如此。它是多项式,所以它比O(n!) 小。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多