我们获得了一组 n 元素,我们希望生成所有 k - 子集。例如,如果 S = {1,2,3} 且 k = 2 ,那么答案将是 {1,2},{1,3 },{2,3} (顺序并不重要)。
{n选择k} k - n -set的子集(按照定义:-),即 O(n ^ k)(虽然这不紧张)。显然,该问题的任何算法都必须及时运行 Omega({n choose k})。
目前最快的已解决此问题的算法是什么?实际上可以实现 {n选择k} 的下限(这样我们有一个基本上最优的算法)?
答案 0 :(得分:2)
有一些众所周知的比特魔法可用于生成所有子集(以长整数的二进制表示法编码):
long getNextSubset(long subset){
long smallest = subset& -subset;
long ripple = subset + smallest;
long ones = subset ^ ripple;
ones = (ones >> 2)/smallest;
subset= ripple | ones;
return subset;
}
void printAllSubsets(int n, int k){
long MAX=1L<<n;
long subset=(1L<<k)-1L;
while((MAX&subset)==0){
System.out.println(Long.toString(subset, 2));
subset=getNextSubset(subset);
}
}
printAllSubsets(4,2)
将按字典顺序生成所有子集:
[00]11
[0]101
[0]110
1001
1010
1100
优点是,这段代码非常快,不足之处 - 它不适用于64个以上的对象。
答案 1 :(得分:0)
这可以使用recusrsive规则计算:
kSubsets(S, k) :
k=0 or k>len(S): {}
else: { for each i-th item in S: {Si} + kSubsets({Si+1,...,Sn}, k-1 }
例如:
kSubsets({1,2,3}, 2) = {
{1}+kSubsets({2,3}, 1)},
{2}+kSubsets({3}, 1)},
{3}+kSubsets({}, 1)
} =
= {
{1}+{{2}+{kSubsets({3},0), {3}+kSubsets({}, 0)}}},
{2}+{{3}+kSubsets({},0)},
{3}+{}
} =
= {
{1}+{{2}+{{}, {3}}},
{2}+this tutorial,
{}
} =
= {
{1}+{{2}, {3}},
{2, 3}
} =
= {
{1, 2}, {1, 3},
{2, 3}
} =
= { {1,2}, {1,3}, {2,3} }
请注意,T + P表示将T项添加到P中的每个项目中(P中的每个项目都是一组)。