【问题标题】:Finding all subsets of a set, Powerset, recursively by cloning n-1 and adding n to the clones通过克隆 n-1 并将 n 添加到克隆中递归地查找集合 Powerset 的所有子集
【发布时间】:2015-10-27 04:24:36
【问题描述】:

拥有集合 {a,b,c} 我想以递归方式找到所有子集。 我已经使用位掩码解决了这个问题,但我想了解一个人在这个 youtube 视频 here

中所说的方式

还有其他关于这个问题的 stackoverflow 线程,但我没有找到任何解决她在视频中陈述的方式的方法,她说,

“取 a 和 b 的子集,克隆它们,然后将 c 添加到所有克隆中”

我无法想象可以实现此目的的“简单”递归方法。递归方法是否一旦用尽,就拥有 A、B 的所有子集和 A、B 的克隆(此时重复),然后传播回来,只将 C 添加到克隆?

换句话说,我从集合上的一个 for 循环开始,我调用我的递归函数,然后我执行一个 n-1 的 for 循环并在该 for 循环中调用我的递归方法,我看不出我怎么能得到将 C 添加到正在使用递归构建的数组中已存在的子集克隆中。

    function SubsetBuilder(set) {
        this.set = set;

    }

    SubsetBuilder.prototype.getSubsetsRecursive = function () {

        //Set = {a,b,c} 
        //take the subsets of a and b, clone them and then add c to all the clones
        //subsets of {a,b}=
        //{}
        //{a}
        //{b}
        //{a,b}
        var n = this.set.length;
        var result = [];
        
        var recurseForSubsets = function (prefix, index) {
            for (var i = index; i < n -1; i ++) {
                result.push(prefix + this.set[i]);
                recurseForSubsets(prefix + this.set[i], i + 1);
            }
        }

        for (var j = 0; j < n; j++) {
            recurseForSubsets("", j);
        }

        return result;
    }

    SubsetBuilder.prototype.printSubsets = function () {
        var self = this;

        if (!self.set)
            return;

        var n = this.set.length;
        for (var i = 0; i < (1 << n) ; i++) {
            var subset = [];
            for (var j = 0; j < n; j++) {
                if (((i >> j) & 1) === 1) { // bit j is on
                    subset.push(this.set[j]);
                }
            }
            console.log(subset);
        }
    }

    var set = ['a', 'b', 'c'];
    var obj = new SubsetBuilder(set);
    //obj.printSubsets();
    console.log(obj.getSubsetsRecursive());

【问题讨论】:

    标签: javascript algorithm recursion


    【解决方案1】:

    我尝试了一下,然后想出了

    function getSubsets(inp) {
      if (inp.length == 1) {
          // return the single item set plus the empty set
          return [inp, []];
      } else {
          var e = inp.pop();
          var s = getSubsets(inp);
          // duplicate the elements of s into s1 without creating references.  
          // this might not be the best technique
          var s1 = s.concat(JSON.parse(JSON.stringify(s)));
          // add e to the second group of duplicates
          for (var i=s.length; i < s1.length; i++) {
              s1[i].push(e);
          }
          return s1;
      }    
    }
    
    var set = ['a', 'b', 'c'];
    var list = getSubsets(set);
    console.log(list);
    
    // result
    //  [["a"], [], ["a", "b"], ["b"], ["a", "c"], ["c"], ["a", "b", "c"], ["b", "c"]]
    

    视频中的女士说,{a,b,c} 的所有子集都可以通过将{a,b} 的所有子集加上c 来形成。不完全准确({a,b,c} 的有效子集不必包括c),而是算法的起点。我将规则更改为{a,b,c} 的所有子集可以通过获取{a,b} 子集的两个副本并将c 附加到第二个副本的每个元素来形成。

    我想我可以去掉或简化if,因为基本上第二个代码块和第一个代码块是一样的,所以它并不理想。

    对我来说,算法在 O(2^n) 中运行是有道理的,因为结果以相同的方式变化(输入数组中的 3 个元素 = 输出数组中的 2^3 个元素) - 你可能不得不原谅我使用JSON 假设复杂性。我会找到一种更好的方法来深度克隆数组,即便如此,这可能会增加更多的复杂性。

    【讨论】:

    • 谢谢我正在研究这个,很快就会回复,你做得很好
    • 这太好了,我希望我能更好地了解你的思维过程,了解你是如何提出这个解决方案的,我理解你的代码 cmets,但我想知道为什么我自己无法找到解决方案,也许是它就像智商一样简单
    • 这个复杂度会是 O(2^n) 吗?
    • @BrianOgden 我希望我已经在答案中解释了自己。
    • 谢谢你,我明白了,我只是希望我能自己想出它,谢谢你的帮助,如果你最近做过复杂性分析,会很高兴告诉你如果这个算法是 O(n^2)?
    猜你喜欢
    • 2021-07-09
    • 1970-01-01
    • 1970-01-01
    • 2014-04-02
    • 1970-01-01
    • 1970-01-01
    • 2015-05-25
    • 2012-10-09
    • 2011-06-15
    相关资源
    最近更新 更多