给定Set
,生成长度为n的所有子集。
示例输入:
set = new Set(['a', 'b', 'c']), length = 2
示例输出:
Set {'a', 'b'}, Set {'a', 'c'}, Set {'b', 'c'}
如何有效地执行此操作,而不将Set
转换为Array
?
我已经为数组输入了一个很好的解决方案:
function* subsets(array, length, start = 0) {
if (start >= array.length || length < 1) {
yield new Set();
} else {
while (start <= array.length - length) {
let first = array[start];
for (subset of subsets(array, length - 1, start + 1)) {
subset.add(first);
yield subset;
}
++start;
}
}
}
let array = ['a', 'b', 'c', 'd'];
for (subset of subsets(array, 2)) {
console.log(...subset);
}
&#13;
然而,我无法为集合提供有效的实现,而无需将集合转换为数组 - 我希望避免使用例如纯粹使用迭代器。
答案 0 :(得分:1)
我实现了删除和重新插入有序多子集的值的想法:
function orderedMultiSubsets(set, n) {
if(!Number.isInteger(n) || n < 0) return function*(){}();
var subset = new Array(n),
iterator = set.values();
return (function* backtrack(index) {
if(index === n) {
yield subset.slice();
} else {
for(var i=0; i<set.size; ++i) {
subset[index] = iterator.next().value; /* Get first item */
set.delete(subset[index]); /* Remove it */
set.add(subset[index]); /* Insert it at the end */
yield* backtrack(index+1);
}
}
})(0);
}
for(var subset of orderedMultiSubsets(new Set([1,2,3]), 2)) {
console.log(subset.join());
}
然后我想我尽可能早地修剪了无序子集的情况:
function subsets(set, n) {
if(!Number.isInteger(n) || n < 0 || n > set.size) return function*(){}();
var subset = new Array(n),
iterator = set.values();
return (function* backtrack(index, remaining) {
if(index === n) {
yield subset.slice();
} else {
for(var i=0; i<set.size; ++i) {
subset[index] = iterator.next().value; /* Get first item */
set.delete(subset[index]); /* Remove it */
set.add(subset[index]); /* Insert it at the end */
if(i <= remaining) {
yield* backtrack(index+1, remaining-i);
}
}
}
})(0, set.size-n);
}
for(var subset of subsets(new Set([1,2,3,4]), 2)) {
console.log(subset.join());
}
我仍然使用数组作为子集,但其大小仅为n
。因此,如果集合的大小比n
大得多,这种方法可能会使用比将数据集复制到数组更少的内存,我想这是你的问题的重点。但请注意,删除和插入可能比数组查找更昂贵。
奖励:最后,集合的顺序与调用函数之前的顺序相同。