什么是生成n组的所有k子集的最有效算法?

时间:2016-03-08 12:10:15

标签: algorithm reference subset combinatorics

我们获得了一组 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} 的下限(这样我们有一个基本上最优的算法)?

2 个答案:

答案 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中的每个项目都是一组)。