以相反的顺序创建过滤后的电源设置

时间:2015-06-02 18:54:46

标签: javascript math combinatorics

我不确定我需要的是否有名字,但它非常接近电源。这就是欲望:

Input:[1,2,3,4]

Output:
[1,2,3,4]
[1,2,3]
[1,2,4]
[1,3,4]
[1,2]
[1,3]
[1,4]

这与3种方式的电源设置不同:

  1. 所有子集都包含第一个值(1
  2. 任何子集的最小尺寸为2
  3. 订单从最长到最短
  4. 我目前的解决方案是创建一个电源设置,过滤掉不以第一个值开始的值,然后反向排序。这太慢了,所以我正在寻找更好的解决方案。

    从最长到最短,我在每个子集上运行测试,直到找到一个返回true的集合。这让我想知道我是否可以使用发电机,所以我不必一次创建所有值(很高兴有,但不是必需的,因为最大尺寸只有~25个成员,或~33MM套)。

    任何帮助表示赞赏!

1 个答案:

答案 0 :(得分:0)

使用位掩码可以轻松生成功率集。

考虑集合A = {1, 2, 3, 4}。定义一个4元素布尔向量并将其表示为I。现在,定义B = { A[i] | I[i] = true }。有两件事需要注意:

  1. B显然是A的一个子集。
  2. 通过迭代I的可能值,我们可以生成所有子集
  3. 整数的位可以用作I,将每个位视为一个布尔值。
  4. 话虽这么说,这是一个生成数组所有子集的算法:

    "use strict";
    var input = [1, 2, 3, 4];
    
    var isMemberInSet = function (indexingVector, _, index) {
        return indexingVector & (1 << index);
    }
    
    var subsetCount = Math.pow(2, input.length);
    for (var indexingVector = 0; indexingVector < subsetCount; indexingVector++) {
        var subset = input.filter(isMemberInSet.bind(undefined, indexingVector));
        console.log(subset);
    }
    

    但我们可以做得更好!事实上,对上述算法的一些简单修改可以完全解决您的问题。

    首先,由于我们需要始终包含数组的第一个值,因此我们需要镜像索引向量生成。换句话说,重新定义B = { A[I.length - i - 1] | I[i] = true }

    其次,我们需要以相反的顺序迭代索引向量,这意味着:

    for (var i = subsetCount - 1; i >= 0; i--)
    

    第三,因为我们不关心所有子集,而只关注那些长度> gt的子集。 2我们不需要一直迭代到0,而只是迭代到pow(2, input.length - 1),因为这是仅包含第一个和第二个值的索引向量,而索引向量的所有其他值都不包括第一个值:

    var subsetsContainingTheFirstValue = Math.pow(2, input.length - 1);
    for (var i = subsetCount - 1; i > subsetsContainingTheFirstValue; i--)
    

    最后,我们得到了这段代码:

    "use strict";   
    var input = [1, 2, 3, 4];
    
    var integerSize = 32;
    
    var isMemberInSet = function (indexingVector , _, index) {
        return indexingVector & (1 << (input.length - index - 1));
    }
    
    var subsetCount = Math.pow(2, input.length);
    var subsetsContainingTheFirstValue = Math.pow(2, input.length - 1);
    for (var indexingVector  = subsetCount - 1; indexingVector  > subsetsContainingTheFirstValue; indexingVector --) {
        var subset = input.filter(isMemberInSet.bind(undefined, indexingVector ));
        console.log(subset);
    }
    

    输出:

    [1, 2, 3, 4]
    [1, 2, 3]
    [1, 2, 4]
    [1, 2]
    [1, 3, 4]
    [1, 3]
    [1, 4]
    

    注意:上面的代码是有效的,因为你提到最大元素数是25.如果这个数字超过32,我们将无法使用整数而且需要布尔数组。