我有一个生成数组的所有子集的方法,我想尝试和实现的方法是相同的方法,但使用二进制方法。 Gosper的Hack似乎是最好的主意,但我不知道如何实现它。下面的代码用于生成所有子集。子集可以是未知的(http://imgur.com/KXflVjq),这表示在运行几秒后输出。感谢您的任何建议
int m = prop.length;
int list = (1 << m);
for(long i = 1; i<list; i++) {
final List sub = new ArrayList<>();
for(long j=0; j<m; j++) {
if((i & (1<<j)) > 0) {
sub.add(j);
}
}
Collections.sort(sub);
System.out.println(sub);
}
编辑:由于我没有正确地说明这个问题,我需要的是输出:
2 1 0
0 0 1 = 0
0 1 0 = 1
等
答案 0 :(得分:2)
首先,我要注意它不清楚你究竟想要达到的目的是什么;请考虑澄清问题。我假设您要生成 n -set的所有 k 子集。这个问题可以很容易地减少到生成 {1,2,...,n} 的所有 k 子集的问题(即它足以计算所有 k -subsets of indices)。
前段时间我写了一个方法(我几年前重新发现)的this实现,用于生成 n -set的所有 k - 子集。希望能帮助到你。该算法基本上以一种聪明的方式访问所有长度为 n 的二进制序列,其中包含 k ,不经过所有2 ^ n个序列;请参阅描述算法的the accompanying note,其中包含详细说明,伪代码和一个小步骤示例。
我认为时间复杂度是 O(k {n choose k})的顺序。我还没有这方面的正式证据。 (很明显,任何算法都必须采用 Omega({n choose k})时间。)
C中的代码:
#include <stdlib.h>
#include <stdio.h>
void subs(int n, int k);
int main(int argc, char **argv)
{
if(argc != 3) return 1;
int n, k;
n = atoi(argv[1]); k = atoi(argv[2]);
subs(n, k);
return 0;
}
void subs(int n, int k)
{
int *p = (int *)malloc(sizeof(int)*k);
int i, j, r;
for(i = 0; i < k; ++i) p[i] = i; // initialize our ``set''
// the algorithm
while(1)
{ // visit the current k-subset
for(i = 0; i < k; ++i)
printf("%d ", p[i]+1);
printf("\n");
if(p[0] == n-k) break; // if this is the last k-subset, we are done
for(i = k-1; i >= 0 && p[i]+k-i == n; --i); // find the right element
r = p[i]; ++p[i]; j = 2; // exchange them
for(++i; i < k; ++i, ++j) p[i] = r+j; // move them
}
free(p);
}
如果这还不够有效,我强烈推荐Knuth的Volume 4 of The Art of Comouter Programming,他在那里广泛处理这个问题。它可能是那里最好的参考(也是最近的!)。
您甚至可以找到分册的草稿,TAOCP第4卷第3章,生成所有组合和分区(2005),vi + 150pp。国际标准书号0-201-85394-9,在Knuth的主页上(见他2011年左右的新闻)。