查找集合的所有子集

时间:2009-04-08 08:06:20

标签: c++ math

我需要一个算法来查找集合中所有子集的子集,n

S={1,2,3,4...n}

编辑:我无法理解到目前为止提供的答案。我想逐步了解答案如何找到子集。

例如,

S={1,2,3,4,5}

您如何知道{1}{1,2}是子集?

有人可以帮我用c ++中的一个简单函数来查找{1,2,3,4,5}的子集

21 个答案:

答案 0 :(得分:104)

递归执行此操作非常简单。基本思想是,对于每个元素,子集的集合可以平均分为包含该元素的子集和不包含该元素的子集,并且这两个集合在其他方面是相等的。

  • 对于n = 1,子集集合为{{},{1}}
  • 对于n> 1,找到1,...,n-1的子集集合并制作它的两个副本。对于其中一个,将n添加到每个子集。然后取两份的联合。

修改为了清晰起见:

  • {1}的子集集为{{},{1}}
  • 对于{1,2},选择{{},{1}},为每个子集添加2以获取{{2},{1,2}},并使用{{},{1}进行联合获取{{},{1},{2},{1,2}}
  • 重复直到你到达

答案 1 :(得分:50)

回答太迟了,但这里的迭代方法听起来很容易:

1)对于一组n元素,获取2^n的值。将有2 ^ n个子集。 (2 ^ n因为每个元素可以存在(1)或不存在(0)。因此对于n个元素,将存在2 ^ n个子集。)。例如:
for 3 elements, say {a,b,c}, there will be 2^3=8 subsets

2)获取2^n的二进制表示。例如:
8 in binary is 1000

3)从0转到(2^n - 1)。在每次迭代中,对于二进制表示中的每个1,形成具有与二进制表示中的1的索引相对应的元素的子集。 例如:

For the elements {a, b, c}
000 will give    {}
001 will give    {c}
010 will give    {b}
011 will give    {b, c}
100 will give    {a}
101 will give    {a, c}
110 will give    {a, b}
111 will give    {a, b, c}

4)执行步骤3中找到的所有子集的并集。返回。例如:
Simple union of above sets!

答案 2 :(得分:24)

如果其他人过来并且仍在疑惑,这里是使用Michael在C ++中的解释的函数

vector< vector<int> > getAllSubsets(vector<int> set)
{
    vector< vector<int> > subset;
    vector<int> empty;
    subset.push_back( empty );

    for (int i = 0; i < set.size(); i++)
    {
        vector< vector<int> > subsetTemp = subset;

        for (int j = 0; j < subsetTemp.size(); j++)
            subsetTemp[j].push_back( set[i] );

        for (int j = 0; j < subsetTemp.size(); j++)
            subset.push_back( subsetTemp[j] );
    }
    return subset;
}

但是,考虑到这将返回一组大小为2 ^ N且包含所有可能的子集,这意味着可能存在重复项。如果您不想这样,我建议实际使用set而不是vector(我曾经在代码中避免使用迭代器)。

答案 3 :(得分:8)

如果您想枚举所有可能的子集,请查看this论文。他们讨论了不同的方法,如词典顺序,灰色编码和银行家的序列。它们给出了银行家序列的示例实现,并讨论了解决方案的不同特征,例如性能

答案 4 :(得分:6)

在这里,我已经详细解释过了。 如果你喜欢这个博文,请做upvote。

http://cod3rutopia.blogspot.in/

如果你在这里找不到我的博客,那么任何方式都是解释。

这是一个本质上是递归的问题。

基本上,对于要出现在子集中的元素,有两个选项:

1)它存在于集合

2)集合中没有。

这就是为什么一组n个数字有2 ^ n个子集的原因。(每个元素有2个选项)

这是打印所有子集的伪代码(C ++),后面是一个解释代码如何工作的示例。 1)A []是要查找其子集的数字数组。 2)bool a []是布尔数组,其中a [i]判断数字A [i]是否存在于集合中。

print(int A[],int low,int high)  
   {
    if(low>high)  
    {
     for(all entries i in bool a[] which are true)  
        print(A[i])
    }  
   else  
   {set a[low] to true //include the element in the subset  
    print(A,low+1,high)  
    set a[low] to false//not including the element in the subset  
    print(A,low+1,high)
   }  
  }  

答案 5 :(得分:4)

这是python中一个简单的递归算法,用于查找集合的所有子集:

def find_subsets(so_far, rest):
        print 'parameters', so_far, rest
        if not rest:
            print so_far
        else:
            find_subsets(so_far + [rest[0]], rest[1:])
            find_subsets(so_far, rest[1:])


find_subsets([], [1,2,3])

输出如下: $ python subsets.py

parameters [] [1, 2, 3]
parameters [1] [2, 3]
parameters [1, 2] [3]
parameters [1, 2, 3] []
[1, 2, 3]
parameters [1, 2] []
[1, 2]
parameters [1] [3]
parameters [1, 3] []
[1, 3]
parameters [1] []
[1]
parameters [] [2, 3]
parameters [2] [3]
parameters [2, 3] []
[2, 3]
parameters [2] []
[2]
parameters [] [3]
parameters [3] []
[3]
parameters [] []
[]

观看以下来自斯坦福的视频,了解该算法的一个很好的解释:

https://www.youtube.com/watch?v=NdF1QDTRkck&feature=PlayList&p=FE6E58F856038C69&index=9

答案 6 :(得分:3)

你不必乱用递归和其他复杂的算法。您可以使用0到2 ^(N-1)之间所有数字的位模式(十进制到二进制)找到所有子集。这里N是该集合中的基数或项目数。这里介绍了该技术的实现和演示。

http://codeding.com/?article=12

答案 7 :(得分:3)

这是Michael针对std :: vector中任何类型元素的解决方案的实现。

#include <iostream>
#include <vector>

using std::vector;
using std::cout;
using std::endl;

// Find all subsets
template<typename element>
vector< vector<element> > subsets(const vector<element>& set)
{
  // Output
  vector< vector<element> > ss;
  // If empty set, return set containing empty set
  if (set.empty()) {
    ss.push_back(set);
    return ss;
  }

  // If only one element, return itself and empty set
  if (set.size() == 1) {
    vector<element> empty;
    ss.push_back(empty);
    ss.push_back(set);
    return ss;
  }

  // Otherwise, get all but last element
  vector<element> allbutlast;
  for (unsigned int i=0;i<(set.size()-1);i++) {
    allbutlast.push_back( set[i] );
  }
  // Get subsets of set formed by excluding the last element of the input set
  vector< vector<element> > ssallbutlast = subsets(allbutlast);
  // First add these sets to the output
  for (unsigned int i=0;i<ssallbutlast.size();i++) {
    ss.push_back(ssallbutlast[i]);
  }
  // Now add to each set in ssallbutlast the last element of the input
  for (unsigned int i=0;i<ssallbutlast.size();i++) {
    ssallbutlast[i].push_back( set[set.size()-1] );
  }
  // Add these new sets to the output
  for (unsigned int i=0;i<ssallbutlast.size();i++) {
    ss.push_back(ssallbutlast[i]);
  }

  return ss;

}

// Test
int main()
{

  vector<char> a;
  a.push_back('a');
  a.push_back('b');
  a.push_back('c');


  vector< vector<char> > sa = subsets(a);

  for (unsigned int i=0;i<sa.size();i++) {
    for (unsigned int j=0;j<sa[i].size();j++) {
      cout << sa[i][j];
    }
    cout << endl;
  }

  return 0;

}

输出:

(empty line)
a
b
ab
c
ac
bc
abc

答案 8 :(得分:2)

以下是Scala中的解决方案:

def subsets[T](s : Set[T]) : Set[Set[T]] = 
  if (s.size == 0) Set(Set()) else { 
    val tailSubsets = subsets(s.tail); 
    tailSubsets ++ tailSubsets.map(_ + s.head) 
} 

答案 9 :(得分:2)

这是一些伪代码。如果调用值已经存在,您可以通过在递归调用检查之前存储每个调用的值来剪切相同的递归调用。

以下算法将包含除空集之外的所有子集。

list * subsets(string s, list * v){
    if(s.length() == 1){
        list.add(s);    
        return v;
    }
    else
    {
        list * temp = subsets(s[1 to length-1], v);     
        int length = temp->size();

        for(int i=0;i<length;i++){
            temp.add(s[0]+temp[i]);
        }

        list.add(s[0]);
        return temp;
    }
}

答案 10 :(得分:2)

这是我前段时间写的一段工作代码

// Return all subsets of a given set
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>
#include<sstream>
#include<cstring>
#include<climits>
#include<cmath>
#include<iterator>
#include<set>
#include<map>
#include<stack>
#include<queue>
using namespace std;


typedef vector<int> vi;
typedef vector<long long> vll;
typedef vector< vector<int> > vvi;
typedef vector<string> vs;

vvi get_subsets(vi v, int size)
{
    if(size==0) return vvi(1);
    vvi subsets = get_subsets(v,size-1);

    vvi more_subsets(subsets);

    for(typeof(more_subsets.begin()) it = more_subsets.begin(); it !=more_subsets.end(); it++)
    {
        (*it).push_back(v[size-1]);
    }

    subsets.insert(subsets.end(), (more_subsets).begin(), (more_subsets).end());
    return subsets;
}

int main()
{
    int ar[] = {1,2,3};
    vi v(ar , ar+int(sizeof(ar)/sizeof(ar[0])));
    vvi subsets = get_subsets(v,int((v).size()));


    for(typeof(subsets.begin()) it = subsets.begin(); it !=subsets.end(); it++)
    {
        printf("{ ");

        for(typeof((*it).begin()) it2 = (*it).begin(); it2 !=(*it).end(); it2++)
        {
            printf("%d,",*it2 );
        }
        printf(" }\n");
    }
    printf("Total subsets = %d\n",int((subsets).size()) );
}

答案 11 :(得分:2)

使用O(n)空间解决方案自下而上

#include <stdio.h>

void print_all_subset(int *A, int len, int *B, int len2, int index)
{
    if (index >= len)
    {
        for (int i = 0; i < len2; ++i)
        {
            printf("%d ", B[i]);
        }
        printf("\n");

        return;
    }
    print_all_subset(A, len, B, len2, index+1);

    B[len2] = A[index];
    print_all_subset(A, len, B, len2+1, index+1);
}



int main()
{
    int A[] = {1, 2, 3, 4, 5, 6, 7};
    int B[7] = {0};

    print_all_subset(A, 7, B, 0, 0);
}

答案 12 :(得分:0)

Swift 中的递归解决方案,按照公认的:

private func getSubsets(_ set: Set<Int>) -> Set<Set<Int>> {

    var set = set // Allows you to manipulate the set

    if set.isEmpty { // Base Case: Subset of an empty set is an empty set
    
        return [[]]
    
    } else { // Remove n, find subset of 1,...,n - 1, duplicate subset and append n to duplicated set, return the union of both
    
        let n = set.removeFirst()
    
        var subset = getSubsets(set)
    
        for i in subset {
            var temp = i
            temp.insert(n)
            subset.insert(temp)
        }
    
        return subset
    
    }

}

答案 13 :(得分:0)

这是原始答案的代码

    void print_subsets(std::vector<int>& nums, int i, std::vector<std::vector<int>>& results, std::vector<int>& r) {    
        if (i < nums.size()) {    
            r.push_back(nums[i]);  // First consider the element
            print_subsets(nums, i + 1, results, r);
            r.pop_back(); // Now don't consider the element
            print_subsets(nums, i + 1, results, r);
        }
        else {
            results.push_back(r);
        }     
    }

// Main method
   vector<vector<int>> subsets(vector<int>& nums) {
        std::vector<std::vector<int>> results;
        std::vector<int> r;
        print_subsets(nums, 0, results, r);        
        return results;
    }

答案 14 :(得分:0)

 vector<vetor<int>> subarrays(vector<int>& A) {
        vector<vetor<int>> set;
        vector<vector<int>> tmp;
        
        set.push_back({});
        set.push_back({});
        set[1].push_back(A[0]);
        
        for(int i=1;i<A.size();i++){
            tmp=set;
            for(int j=0;j<tmp.size();j++){
                tmp[j].push_back(A[i]);
            }
            set.insert( set.end(), tmp.begin(), tmp.end() );
        }
        return set;
    }

答案 15 :(得分:0)

一种优雅的递归解决方案,与上面的最佳答案说明相对应。核心向量运算只有4行。归功于安蒂(Antti)Laaksonen撰写的“竞争性编程指南”一书。

// #include <iostream>
#include <vector>
using namespace std;

vector<int> subset;
void search(int k, int n) {
    if (k == n+1) {
    // process subset - put any of your own application logic
    // for (auto i : subset) cout<< i << " ";
    // cout << endl;
    }
    else {
        // include k in the subset
        subset.push_back(k);
        search(k+1, n);
        subset.pop_back();
        // don't include k in the subset
        search(k+1,n);
    }
}

int main() {
    // find all subset between [1,3]
    search(1, 3);
}

答案 16 :(得分:0)

  

这个问题很老了。但OP有一个简单优雅的递归解决方案。

using namespace std;
void recsub(string sofar, string rest){
  if(rest=="") cout<<sofar<<endl;
  else{
    recsub(sofar+rest[0], rest.substr(1)); //including first letter
    recsub(sofar, rest.substr(1)); //recursion without including first letter.
  }
}
void listsub(string str){
  recsub("",str);
}
int main(){
  listsub("abc");
  return 0;
}

//output
abc
ab
ac
a
bc
b
c

//end: there's a blank output too representing empty subset

答案 17 :(得分:0)

对于那些想要使用std :: vector和std :: set进行Michael Borgwardt算法的简单实现的人:

// Returns the subsets of given set
vector<set<int> > subsets(set<int> s) {
    vector<set<int> > s1, s2;
    set<int> empty;
    s1.push_back(empty); // insert empty set
    // iterate over each element in the given set
    for(set<int>::iterator it=s.begin(); it!=s.end(); ++it) {
        s2.clear(); // clear all sets in s2
        // create subsets with element (*it)
        for(vector<set<int> >::iterator s1iter=s1.begin(); s1iter!=s1.end(); ++s1iter) {
            set<int> temp = *s1iter;
            temp.insert(temp.end(), *it);
            s2.push_back(temp);
        }
        // update s1 with new sets including current *it element
        s1.insert(s1.end(), s2.begin(), s2.end());
    }
    // return
    return s1;
}

答案 18 :(得分:0)

一个简单的位掩码可以解决前面讨论过的问题....由rgamber

#include<iostream>
#include<cstdio>

#define pf printf
#define sf scanf

using namespace std;

void solve(){

            int t; char arr[99];
            cin >> t;
            int n = t;
            while( t-- )
            {
                for(int l=0; l<n; l++) cin >> arr[l];
                for(int i=0; i<(1<<n); i++)
                {
                    for(int j=0; j<n; j++)
                        if(i & (1 << j))
                        pf("%c", arr[j]);
                    pf("\n");
                }
            }
        }

int main() {
      solve();
      return 0;
}

答案 19 :(得分:0)

这是我的递归解决方案。

vector<vector<int> > getSubsets(vector<int> a){


//base case
    //if there is just one item then its subsets are that item and empty item
    //for example all subsets of {1} are {1}, {}

    if(a.size() == 1){
        vector<vector<int> > temp;
        temp.push_back(a);

        vector<int> b;
        temp.push_back(b);

        return temp;

    }
    else
    {


         //here is what i am doing

         // getSubsets({1, 2, 3})
         //without = getSubsets({1, 2})
         //without = {1}, {2}, {}, {1, 2}

         //with = {1, 3}, {2, 3}, {3}, {1, 2, 3}

         //total = {{1}, {2}, {}, {1, 2}, {1, 3}, {2, 3}, {3}, {1, 2, 3}}

         //return total

        int last = a[a.size() - 1];

        a.pop_back();

        vector<vector<int> > without = getSubsets(a);

        vector<vector<int> > with = without;

        for(int i=0;i<without.size();i++){

            with[i].push_back(last);

        }

        vector<vector<int> > total;

        for(int j=0;j<without.size();j++){
            total.push_back(without[j]);
        }

        for(int k=0;k<with.size();k++){
            total.push_back(with[k]);
        }


        return total;
    }


}

答案 20 :(得分:0)

一种简单的方法是以下伪代码:

Set getSubsets(Set theSet)
{
  SetOfSets resultSet = theSet, tempSet;


  for (int iteration=1; iteration < theSet.length(); iteration++)
    foreach element in resultSet
    {
      foreach other in resultSet
        if (element != other && !isSubset(element, other) && other.length() >= iteration)
          tempSet.append(union(element, other));
    }
    union(tempSet, resultSet)
    tempSet.clear()
  }

}

嗯,我并不完全确定这是对的,但看起来还不错。