假设我们有这样一个数组: myArray = [A,A,B,B,C,C,D,E]
我想创建一种算法,以便找到所有加在整个数组上的组合,其中没有重复任何元素。
示例组合:
[A, B, C, D, E] [A, B, C]
[A, B, C, D] [A, B, C, E]
[A, B, C] [A, B, C] [D, E]
说明:[A, B, C] [A, B, C] [D, E]
和[A, B, C] [D, E] [A, B, C]
是相同的组合。同样,子集的排序也无关紧要。例如,[A,B,C]
和[B,A,C]
应该相同。
到目前为止,我没有超越
var myArray = ["A", "A", "B", "B", "C", "C", "D", "E"]
console.log([...new Set(myArray)])
但这完全没有帮助,它只返回一个不同的集合。 我找不到以前发布的类似问题,所以有人可以在这里指导我如何实现此目标吗?
答案 0 :(得分:3)
我得到315种组合。那正确吗? :)
这是递归:
function distribute(e, i, _comb){
// No more e's
if (e[1] == 0)
return [_comb];
// We're beyond the combination
if (i == -1)
return [_comb.concat([e])];
let result = [];
for (let c=1; c<=Math.min(_comb[i][1], e[1]); c++){
let comb = _comb.map(x => x.slice());
if (c == comb[i][1]){
comb[i][0] += e[0];
} else {
comb[i][1] -= c;
comb.push([comb[i][0] + e[0], c]);
}
result = result.concat(distribute([e[0], e[1] - c], i - 1, comb));
}
let comb = _comb.map(x => x.slice());
return result.concat(distribute(e, i - 1, comb));
}
function f(arr){
function g(i){
if (i == 0)
return [[arr[0]]];
const combs = g(i - 1);
let result = [];
for (let comb of combs)
result = result.concat(
distribute(arr[i], comb.length - 1, comb));
return result;
}
return g(arr.length - 1);
}
function show(arr){
const rs = f(arr);
const set = new Set();
for (let r of rs){
const _r = JSON.stringify(r);
if (set.has(_r))
console.log('Duplicate: ' + _r);
set.add(_r);
}
let str = '';
for (let r of set)
str += '\n' + r
str += '\n\n';
console.log(JSON.stringify(arr));
console.log(set.size + ' combinations:');
console.log(str);
}
show([['A', 2], ['B', 2], ['C', 2], ['D', 1], ['E', 1]]);
答案 1 :(得分:1)
这会生成所需结果的所有可能排列,因此无法回答问题。
function* combinations(combos) {
yield combos;
for(const [i1, group] of combos.entries()) {
for(const [i2, group2] of combos.slice(i1 + 1).entries()) {
if(group.some(v => group2.includes(v))) continue;
yield* combinations([
...combos.filter((_, index) => index !== i1 && index !== i2),
[...group, ...group2]
]);
}
}
}
console.log([...combinations([1, 2, 3, 4, 1].map(v => ([v])))]);
您可以从包含仅包含一个元素的组合的数组开始,然后遍历这些组合并合并其中的两个数组,然后递归进行。
答案 2 :(得分:1)
您可以通过枚举所有可能的组合,然后为每个组合找到置换来完成,然后过滤该元素以确保它们是唯一的。可以通过插入Set来完成此过滤。
子集函数来自@le_m(Check this answer)。
function* subsets(array, offset = 0) {
while (offset < array.length) {
let first = array[offset++];
for (let subset of subsets(array, offset)) {
subset.push(first);
yield subset;
}
}
yield [];
}
function* permutations(elements) {
if (elements.length === 1) {
yield elements;
} else {
let [first, ...rest] = elements;
for (let perm of permutations(rest)) {
for (let i = 0; i < elements.length; i++) {
let start = perm.slice(0, i);
let rest = perm.slice(i);
yield [...start, first, ...rest];
}
}
}
}
const arr = ['A', 'a', 'B', 'b', 'C', 'c', 'd', 'e'];
const results = new Set();
for (let subset of subsets(arr)) {
if (subset.length) {
for (let permut of permutations(subset)) {
results.add(permut.join(''));
}
}
}
console.log([...results]);
答案 3 :(得分:1)
您可以先对相同的元素进行分组并对其进行计数,从而得到如下表:
1 | 2 | 3 | 4
1 | | 3 | 4
1
(重复1次,重复3次和4次)
现在您可以开始并取出前四个元素,然后在第二行中取出3个,然后在最后一行中取出一个,
[[1, 2, 3, 4], [1, 3, 4], [1]]
现在要获取下一个组合,只需从第一行中取出3个,然后将其他值向上移动:
1 | | 3 | 4
1 | | | 4
现在再次取出行,您会得到
[[1, 2, 3], [1, 3, 4], [1, 4]]
现在,在第一行(采用2、1)重复此模式,依此类推,再对各行重复此模式,那么您应该获得想要获得的结果。
const counts = new Map;
for(const value of [1, 1, 1, 2, 3, 3, 4, 4])
counts.set(value, (counts.get(value) || 0) + 1);
const result = [];
for(let combo = 0; combo < counts.size; combo++) {
const subResult = [];
const combos = [...counts];
for(let i = 0; i <= combo; i++) combos[i][0] -= 1;
subResult.push(combos.slice(0, combo).map(([_, value]) => value);
while(combos.some(([count]) => count > 0)) {
subResult.push(combos.filter(([count]) => count > 0).map(([_, value] => value));
}
result.push(subResult);
}
答案 4 :(得分:1)
从头开始实施一种算法:
const decrementKey = (o, k) => o[k]--;
const isEmpty = (o) => Object.keys(o).length === 0;
const removeKeys = (o) => Object.keys(o).forEach(k => { if (o[k] < 1) delete o[k]; });
const frequencyMap = (a) => a.reduce((r, v) => Object.assign(r, { [v] : (r[v] || 0) + 1 }), {});
const cloneMap = (o) => Object.keys(o).reduce((r, k) => Object.assign(r, { [k] : o[k] }), {});
let myArray = ["A", "A", "B", "B", "C", "C", "D", "E"];
let groups = solve(myArray);
console.log(groups.map(g => g.map(a => a.join('')).join(' | ')).join('\n'));
function solve(arr) {
let freq = frequencyMap(arr), results = [];
for (let max = Object.keys(freq).length; max > 1; max--) {
let result = [], clone = cloneMap(freq);
while (!isEmpty(clone)) {
result.push(Object.keys(clone).reduce((res, key, index) => {
if (index < max) {
decrementKey(clone, key);
res.push(key);
}
return res;
}, []));
removeKeys(clone);
}
if (result.length > 0) results.push(result);
}
return results;
}
.as-console-wrapper { top: 0; max-height: 100% !important; }