5

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

如何迭代所有大小为 k 的子集(对于 (0 <= k <= n))?这是一场表演噩梦吗?我知道有 (n, k) = n!/k!(n - k)!可能性。我知道如果 k 非常接近 0 或非常接近 n,这是一个很小的数字。

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

4

2 回答 2

10

你想要 Gosper 的 hack:

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 块”数字的方法是将最高位向左移动一个,并将所有其他位尽可能低。Gospera的hack 通过找到最低设置位 ( b- 重要的位。

于 2013-04-10T18:56:09.367 回答
0

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

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

于 2014-06-17T00:33:00.840 回答