【问题标题】:Finding all the subsets of a set查找集合的所有子集
【发布时间】:2009-04-08 08:06:19
【问题描述】:

我需要一种算法来查找集合中元素数为n 的集合的所有子集。

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

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

例如,

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

你怎么知道{1}{1,2} 是子集?

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

【问题讨论】:

  • 这个问题很模糊,你的意思是所有可能的子集吗?
  • 子集的数量不是 n!那就是排列的数量。子集的数量(幂集的基数)是 2^n

标签: c++ algorithm math subset


【解决方案1】:

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

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

编辑使其一目了然:

  • {1} 的子集集是 {{}, {1}}
  • 对于 {1, 2},取 {{}, {1}},每个子集加 2 得到 {{2}, {1, 2}} 并取与 {{}, {1} 的并集} 得到 {{}, {1}, {2}, {1, 2}}
  • 重复直到达到 n

【讨论】:

  • 谢谢,但我仍然无法确定如何将 2 添加到每个子集以及如何使用联合...请您使用此集进行描述 {1,2,3,4,5 }
  • 我的意思是,如果你告诉我你在算法或 c/c++ 程序中的例子。
  • 真正的基本情况应该是“{} 的幂集是 {{}}。”那么 {n} 的 poserset 是 {{}} union {n}。等等。
  • 没错,但我认为这样更容易理解。
  • 这里的答案较晚:与上述解释相对应的优雅递归解决方案。核心向量运算只有 4 行。归功于安蒂的 Laaksonen 的“竞争编程指南”一书。请参阅下面答案中的代码stackoverflow.com/a/53033401/1586437
【解决方案2】:

回答为时已晚,但迭代方法在这里听起来很容易:

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!

【讨论】:

  • 您的解决方案将如何处理 n > 32 ?我猜你在int.No 中节省了 2^n?
  • 抱歉,我还没有编写任何实现上述内容的代码,但是对于 n>32 来说,使用 int32 会是一个问题 :)。 Michael Borgwardt 在上面提到了另一种解决方案。
  • 我们可以使用大小为 n 的位数组代替整数,并使用整数来迭代所有子集。如果有人感兴趣,可以在这里发布我的答案。
  • 出于任何实际原因,long 已经绰绰有余了。
【解决方案3】:

如果其他人路过仍然想知道,这里有一个使用 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;  //making a copy of given 2-d vector.

        for (int j = 0; j < subsetTemp.size(); j++)
            subsetTemp[j].push_back( set[i] );   // adding set[i] element to each subset of subsetTemp. like adding {2}(in 2nd iteration  to {{},{1}} which gives {{2},{1,2}}.

        for (int j = 0; j < subsetTemp.size(); j++)
            subset.push_back( subsetTemp[j] );  //now adding modified subsetTemp to original subset (before{{},{1}} , after{{},{1},{2},{1,2}}) 
    }
    return subset;
}

但请注意,这将返回一组大小为 2^N 的集合,其中包含所有可能的子集,这意味着可能会有重复。如果你不想要这个,我建议实际上使用 set 而不是 vector(我曾经在代码中避免使用迭代器)。

【讨论】:

【解决方案4】:

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

【讨论】:

    【解决方案5】:

    这里,我已经详细解释过了。 如果您喜欢这篇博文,请点赞。

    http://cod3rutopia.blogspot.in/

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

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

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

    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)
       }  
      }  
    

    【讨论】:

    • 博客不在线怎么办?还是只是停机维护?在您的答案中提供源代码,不要链接到它。
    • OK Manuel,但问题是我不想仅仅提供源代码。我有一个解释,我不想把所有的东西都写一遍。
    • 如果您的博文中已经解释了所有内容,只需复制+粘贴即可?
    • 我已经进行了更改。
    【解决方案6】:

    自底向上 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);
    }
    

    【讨论】:

      【解决方案7】:

      这是一个简单的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 子集.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
      

      【讨论】:

        【解决方案8】:

        这是迈克尔解决方案的一个实现,适用于 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
        

        【讨论】:

          【解决方案9】:

          一个优雅的递归解决方案,对应于上面的最佳答案解释。核心向量运算只有 4 行。归功于安蒂的 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);
          }
          

          【讨论】:

            【解决方案10】:

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

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

            【讨论】:

              【解决方案11】:

              这是 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) 
              } 
              

              【讨论】:

                【解决方案12】:

                这是一些伪代码。您可以通过在执行过程中存储每个调用的值以及在递归调用之前检查调用值是否已经存在来减少相同的递归调用。

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

                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;
                    }
                }
                

                【讨论】:

                  【解决方案13】:

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

                  // 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()) );
                  }
                  

                  【讨论】:

                  【解决方案14】:

                  这个问题很老了。但是对于 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
                  

                  【讨论】:

                    【解决方案15】:

                    一个简单的方法是下面的伪代码:

                    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()
                      }
                    
                    }
                    

                    好吧,我不确定这是否正确,但看起来还可以。

                    【讨论】:

                      【解决方案16】:

                      这是我的递归解决方案。

                      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;
                          }
                      
                      
                      }
                      

                      【讨论】:

                        【解决方案17】:

                        一个简单的位掩码可以解决前面讨论的问题.... by 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;
                        }
                        

                        【讨论】:

                          【解决方案18】:

                          对于那些想要使用 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;
                          }
                          

                          【讨论】:

                            【解决方案19】:
                             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;
                                }
                            

                            【讨论】:

                              【解决方案20】:

                              这是原始答案的代码

                                  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;
                                  }
                              

                              【讨论】:

                                【解决方案21】:

                                根据公认的 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
                                    
                                    }
                                
                                }
                                

                                【讨论】:

                                  【解决方案22】:

                                  基于上述“Michael Borgwardt”算法的无递归Java版本。

                                  public static List powerset(List array) { List perms = new ArrayList(); 如果(数组大小()==0){ perms.add(new ArrayList()); 退货烫发; } 返回powerset(数组,烫发); }

                                  public static List<List<Integer>> powerset(List<Integer> array, List<List<Integer>> perms) {
                                      
                                      for(int i=0;i<array.size();i++){
                                          perms.add(Arrays.asList(array.get(i)));
                                          int x=perms.size();
                                          for(int j=0;j<x;j++){
                                              List<Integer> tmp = new ArrayList<Integer>(perms.get(j));   
                                              if(!(tmp.size()==1 && tmp.get(0)==array.get(i))){
                                                  tmp.add(array.get(i));
                                                  perms.add(tmp);
                                              }
                                          }
                                      }
                                      perms.add(new ArrayList<Integer>());
                                  return perms;
                                  

                                  }

                                  【讨论】:

                                    猜你喜欢
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2011-05-03
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    相关资源
                                    最近更新 更多