通过克隆n-1并将n添加到克隆

时间:2015-10-26 16:59:01

标签: javascript algorithm recursion

拥有集合{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());

1 个答案:

答案 0 :(得分: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来假设复杂性。我会找到一种更好的方法来深度克隆数组,即便如此,这可能会增加更多的复杂性。