【问题标题】:How to generate a power set of a given set?如何生成给定集合的幂集?
【发布时间】:2014-06-23 12:28:30
【问题描述】:

我正在准备面试,我在网上的“数学”类别下偶然发现了这个问题。

生成给定集合的幂集:

int A[] = {1,2,3,4,5};  
int N = 5; 
int Total = 1 << N;
for ( int i = 0; i < Total; i++ ) { 
 for ( int j = 0; j < N; j++) {
  if ( (i >> j) & 1 ) 
      cout << A[j]; 
   } 
 cout <<endl;

 }

我不想要一个明确的答案。我只是想要澄清和提示如何解决这个问题。

我在 google 上查看了功率集算法,但我仍然不明白如何解决这个问题。

另外,有人可以重申一下这个问题的要求吗?

谢谢。

【问题讨论】:

  • 集合的幂集={a,b} 是由集合中表示元素的所有可能组合组成的集合,一次取任意或不取。这里,P(s)={{a},{b},{ab},{}};
  • 对这个问题的递归算法非常感兴趣!

标签: algorithm math powerset


【解决方案1】:

Power set of a set A is the set of all of the subsets of A.

这不是世界上最友好的定义,但举个例子会有所帮助:

例如。对于{1, 2},子集是:{}, {1}, {2}, {1, 2}

因此,幂集是{{}, {1}, {2}, {1, 2}}


要生成幂集,请观察如何创建子集:逐个访问每个元素,然后要么保留它,要么忽略它。

让这个决定用一个位 (1/0) 来表示。

因此,要生成{1},您将选择1 并删除2 (10)。

在类似的行上,您可以为所有子集编写一个位向量:

  • {} -> 00
    {1} -> 10
    {2} -> 01
    {1,2} -> 11

重申:如果通过包含原始集合的部分或全部元素而形成的子集。因此,要创建一个子集,您需要访问每个元素,然后决定是保留它还是删除它。这意味着对于每个元素,您有 2 个决定。因此,对于一个集合,您最终可以得到 2^N 不同的决策,对应于 2^N 不同的子集。

看看你能不能从这里拿走。

【讨论】:

    【解决方案2】:

    创建一个幂集:{"A", "B", "C"}


    伪代码:

    val set = {"A", "B", "C"}
    
    val sets = {}
    
    for item in set:
      for set in sets:
        sets.add(set + item)
      sets.add({item})
    sets.add({})
    

    算法说明:

    1) 将sets 初始化为一个空集:{}

    2) 遍历{"A", "B", "C"}中的每一项

    3) 遍历sets 中的每个set

    3.1) 创建一个新集合,它是set 的副本。

    3.2) 将item 附加到new set

    3.3) 将new set 附加到sets

    4) 将item 添加到您的sets

    4) 迭代完成。将空集添加到您的 resultSets


    演练:

    我们看一下每次迭代后sets的内容:

    迭代 1,item = "A":

    sets = {{"A"}}
    

    迭代 2,item = "B":

    sets = {{"A"}, {"A", "B"}, {"B"}}
    

    迭代 3,item = "C":

    sets = {{"A"}, {"A", "B"}, {"B"}, {"A", "C"}, {"A", "B", "C"}, {"B", "C"}, {"C"}}
    

    迭代完成,添加空集:

    sets = {{"A"}, {"A", "B"}, {"B"}, {"A", "C"}, {"A", "B", "C"}, {"B", "C"}, {"C"}, {}}
    

    集合的大小是 2^|set| = 2^3 = 8 这是正确的。


    Java 中的示例实现:

    public static <T> List<List<T>> powerSet(List<T> input) {
      List<List<T>> sets = new ArrayList<>();
      for (T element : input) {
        for (ListIterator<List<T>> setsIterator = sets.listIterator(); setsIterator.hasNext(); ) {
          List<T> newSet = new ArrayList<>(setsIterator.next());
          newSet.add(element);
          setsIterator.add(newSet);
        }
        sets.add(new ArrayList<>(Arrays.asList(element)));
      }
      sets.add(new ArrayList<>());
      return sets;
    }
    

    输入:[A, B, C]

    输出:[[A], [A, C], [A, B], [A, B, C], [B], [B, C], [C], []]

    【讨论】:

    • 如果您在开头(而不是结尾)添加了{},那么您不必在每次通过外循环时显式插入单例集。
    • @JohnColeman 嗨,约翰,如果我们在开始时添加了一个空集,那么我们将迭代这些集太多次。在第一次迭代之后,我们会得到 {{"A"},{"A"}} 这是不正确的。插入空集也在任何循环之外完成。你介意分享一些代码来解释吗?
    • @JohnColeman 如果我从一个空集{{}} 开始,那么当我遍历这些集时,我将获取空集并将“A”附加到它上面。然后,我将在现有集合中添加一个包含“A”的新集合。根据您的建议运行代码,我在第一次迭代后得到以下信息:[[], [A], [A]] 符合预期。在 {'A', 'B', 'C'} 上运行新算法我得到[[], [C], [B], [B, C], [A], [A, C], [A, B], [A, B, C], [A], [A, C], [A, B], [A, B, C], [B], [B, C], [C]]
    • 您说“然后我将在现有集合中添加一个包含 'A' 的新集合”——但是为什么您仍然会这样做?我的评论的重点是,如果您使用空集进行初始化,则不需要将项目显式添加为单例(伪代码中的第 4 步)
    • @SarahM 我用List 来证明这个算法不会产生重复
    【解决方案3】:

    幂集只是给定集合的所有子集的集合。它包括所有子集(带有空集)。众所周知,这个集合中有 2N 个元素,其中N 是原始集合中的元素个数。

    要构建电源组,可以使用以下内容:

    • 创建一个循环,迭代从 0 到 2 的所有整数N-1
    • 对每个整数进行二进制表示
    • 每个二进制表示都是一组N 位(对于较小的数字,添加前导零)。如果某个集合成员包含在当前子集中,则每个位都对应。

    例如,3 个数字:abc

    number binary  subset
    0      000      {}
    1      001      {c}
    2      010      {b}
    3      011      {b,c}
    4      100      {a}
    5      101      {a,c}
    6      110      {a,b}
    7      111      {a,b,c}
    

    【讨论】:

    • 我们为什么要转换成二进制?我不明白。
    • @PoojaKhatri 二进制数中的每一位表示元素是否存在于当前子集中。查看评分最高的答案以获得更好的解释。
    【解决方案4】:

    好吧,您需要生成所有子集。对于一个大小为 n 的集合,有 2n 个子集。

    一种方法是迭代从 0 到 2n - 1 的数字 并将每个转换为二进制数字列表,其中0 表示排除 该元素和1 表示包含它。

    另一种方法是递归,分而治之。

    【讨论】:

    • 我知道这个线程很旧,但我对递归技术非常感兴趣。这是我从未想过的旧大学 Lisp 作业。我仍然很困惑。
    • @ScottBiggs 我也是……这件事简直令人困惑!
    • 你可以在这里看到一些递归示例:stackoverflow.com/questions/26332412
    【解决方案5】:

    生成集合的所有组合(通过包含或不包含项目)。 举例说明: 一组(或列表)中的 3 个项目。可能的子集是:

    000   
    100   
    010   
    001
    110
    101
    011
    111   
    

    结果是 2^(集合中的元素数)。

    因此,我们可以生成 N 个项目的所有组合(使用 python),如下所示:

    def powerSet(items):
    
        N = len(items)
    
        for i in range(2**N):
    
            comb=[]
            for j in range(N):
                if (i >> j) % 2 == 1:
                    comb.append(items[j])
            yield comb
    
    for x in powerSet([1,2,3]):
        print (x)
    

    【讨论】:

      【解决方案6】:

      通过实施评分最高的答案,您会得到类似的结果。

      def printPowerSet(set,set_size):
      
          # set_size of power set of a set
          # with set_size n is (2**n -1)
          pow_set_size = (int) (math.pow(2, set_size));
          counter = 0;
          j = 0;
      
          # Run from counter 000..0 to 111..1
          for counter in range(0, pow_set_size):
              for j in range(0, set_size):
      
                  # Check if jth bit in the 
                  # counter is set If set then 
                  # pront jth element from set 
                  if((counter & (1 << j)) > 0):
                      print(set[j], end = "");
              print("");
      

      【讨论】:

        【解决方案7】:

        C# 解决方案

        时间复杂度和空间复杂度:O(n*2^n)

         public class Powerset
            {
        
        
                /*
                 P[1,2,3] = [[],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]]
                     */
                public  List<List<int>> PowersetSoln(List<int> array)
                {
        
                    /*
                        We will start with an empty subset
                        loop through the number in the array
                                 loop through subset generated till and add the number to each subsets
        
                      */
        
                    var subsets = new List<List<int>>();
                    subsets.Add(new List<int>());
        
                    for (int i = 0; i < array.Count; i++)
                    {
                        int subsetLen = subsets.Count; 
                        for (int innerSubset = 0; innerSubset < subsetLen; innerSubset++)
                        {
                            var newSubset = new List<int>(subsets[innerSubset]);
                            newSubset.Add(array[i]);
                            subsets.Add(newSubset);
                        }
        
                    }
        
                    return subsets;
                }
            }
        

        【讨论】:

          【解决方案8】:

          示例 Java 代码:

          void printPowerSetHelper(String s, String r) {
              if (s.length() > 0) {
                  printPowerSetHelper(s.substring(1), r + s.charAt(0));
                  printPowerSetHelper(s.substring(1), r);
              } 
              if (r.length() > 0) System.out.println(r);
          }
          
          void printPowerSet(String s) {
              printPowerSetHelper(s,"");
          }
          

          【讨论】:

            猜你喜欢
            • 2014-01-22
            • 2013-09-20
            • 2012-07-19
            • 1970-01-01
            • 2021-03-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多