【问题标题】:Generate all combinations of subsets which contain exactly the elements in the original set生成完全包含原始集合中元素的所有子集组合
【发布时间】:2020-07-09 13:50:08
【问题描述】:

给定1, 2, 3 的幂集,我得到 8 个子集:[][1][2][2,1][3][3][3,1][3,2][3,2,1]。然后我想生成这个新集合的子集,它们正好是原始集合的 1 个。

我的powerset的powerset中的子集数量是256,但只有8个,其中“1”、“2”和“3”各有1个,分别是:

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

有没有一种方法可以在不生成具有 256 个子集的第二个幂集的情况下获得最终集?我正在寻找一种可以扩展到第一组 3 可以有 10 多个元素的方法,因此计算第二个 powerset 效率不高。 请注意,我实际上并不需要有空数组的情况。我的理想答案只包括前 5 个元素。通过专注于 powerset,我可能把自己推到了错误的兔子洞里。它解决了我在 n=7 时遇到的问题,但无法扩展到 n=14。

这是我目前拥有的函数,但是当数组中有 5 个项目时它会失败。我很可能完全从错误的方向来解决这个问题。

function getPowerset(arr) {
    return (function ps(list) {
        if (list.length === 0) {
            return [
                []
            ];
        }
        const head = list.pop();
        const tail = ps(list);
        return [...tail, ...tail.map((e) => [head, ...e])];
    })([...arr]).filter(x => x.length);
}

function getCombinationsOfSet(arr) {
    const subsets = getPowerset(arr);
    const subsetsOfSubsets = getPowerset(subsets);
    return subsetsOfSubsets.filter((subset) => {
        const flattened = subset.flat();
        if (flattened.length !== arr.length) {
            return false;
        }
        let tempArr = [...arr];
        for (let part of flattened) {
            const index = tempArr.indexOf(part);
            if (index === -1) {
                return false;
            }
            tempArr.splice(index, 1);
        }
        return true;
    })
}

console.time('time-taken');
console.log(getCombinationsOfSet([1, 2, 3]));
console.timeEnd('time-taken');

【问题讨论】:

  • 您正在寻找将原始集划分为子集(有时包括空子集)的所有方法,对吗?
  • @ScottHunter 是的。理想情况下,我可以获得所有可能的方法来划分原始集合,以便我可以通过评分函数运行每种可能性来选择最好的。对于我的具体用例,我不希望任何子集的总和大于 X,然后我会选择总和与 X 之间差异最小的那个。
  • 相信你正在寻找原始集的分区(stackoverflow.com/questions/20530128/…

标签: javascript combinations permutation powerset


【解决方案1】:

感谢@SirRaffleBuffle 提供答案的方向。 stackoverflow 问题How to find all partitions of a set 正是我所追求的。

我将该问题https://stackoverflow.com/a/30903689/3972094 的已接受答案移植到了 Javascript,这让我获得了大部分的成功,我添加了一个过滤器来限制分区,让它在合理的时间内以 > 11 的数组大小运行:

function getAllPartitions(fixedParts, suffixElements, filter) {
    let partitions = [];
    if (filter(suffixElements)) {
        partitions.push(fixedParts.concat([suffixElements]));
    }

    const suffixPartitions = getTuplePartitions(suffixElements).filter(x => filter(x.fixedPart));
    for (const suffixPartition of suffixPartitions) {
        const subPartitions = getAllPartitions(fixedParts.concat([suffixPartition.fixedPart]), suffixPartition.suffixPart, filter);
        partitions = partitions.concat(subPartitions);
    }
    return partitions;
}

function getTuplePartitions(elements) {
    if (elements.length < 2) {
        return [];
    }

    const partitions = [];
    for (let pattern = 1; pattern < 1 << (elements.length - 1); pattern++) {
        const resultSets = [[elements[0]], []];

        for (let index = 1; index < elements.length; index++) {
            resultSets[( pattern >> (index - 1)) & 1].push(elements[index]);
        }

        partitions.push({fixedPart: resultSets[0], suffixPart: resultSets[1]});
    }

    return partitions;
}

function sumPart(part) {
    return part.reduce((sum, n) => sum += n, 0)
}

getAllPartitions([], [1, 2, 3, 4, 5], (part) => sumPart(part) <= 7).map(x => JSON.stringify(x));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-11
    • 2011-04-30
    • 2012-12-01
    • 2019-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-16
    相关资源
    最近更新 更多