修改
var Combos = [1, 2, 4],
Target = 4;
for(var i = 0; i < Combos.length; i++){
var Available = [];
for(var j = -1; j < i; j++) Available.push(Combos[j+1]);
for(var k = 0; k < Available.length; k++){
var C = 0;
var Att = 0;
while(C < Target){ C += Available[k]; Att++; }
if(C === Target) console.log(new Int8Array(Att).fill(Available[k]));
}
}
输出:
[1, 1, 1, 1]
[1, 1, 1, 1]
[2, 2]
[1, 1, 1, 1]
[2, 2]
[4]
我不知道为什么我会重复1,1,1,1和2,2,但我正在调查!
我提供的数字数组将是[1,2,4],我正试图找到一个永远适合的目标;我们假设这是4。
如何返回一个组合数组,其中进程重用所提供的数字,例如:我在这里看到的所有问题只使用一次数字,因此这些程序将返回[[4]]
,而我希望结果为[[1, 1, 1, 1], [1, 1, 2], [2, 2], [4]]
。
起初,我想过使用模数来表示:目标是一个整数,如果是这样我们可以立即返回目标/ 1.但老实说,我无法弄清楚逻辑!
我有过的IRC聊天,也许这可能有助于您理解:
13:20 Robinlemon So I have the numbers [1, 2] and I'm trying to make 4 so I want a function that will return [[1, 1, 1, 1], [1, 1 ,2], [2, 2], [4]] -> all the possible combinations to make the target, by reusing the numbers supplied
13:21 kakashiAL how does your function api looks like?
13:21 Robinlemon What do you mean?
13:21 Robinlemon I've scrapped everything
13:21 kakashiAL foo(myArray, combination=
13:21 Robinlemon Because I can't ever work out the logic to do this
13:21 Robinlemon Well I suppose i'd have
13:22 Robinlemon Permutate(Price) => SubPermutate()
13:22 Robinlemon Then return
13:22 Robinlemon and tierate through each sub function
13:22 kakashiAL so you have [1, 2] and you want to make 4, which means you want to have this:
13:22 kakashiAL 1, 1, 1, 1
13:22 kakashiAL 2, 2, 2, 2
13:23 kakashiAL 1, 2, 2, 2
13:23 kakashiAL 1, 1, 2, 2
13:23 kakashiAL and so on
13:23 kakashiAL right?
13:26 Robinlemon yep
13:26 Robinlemon well no
13:26 Robinlemon The numbers need to add to 4
13:26 Robinlemon so it wouldnt be 1, 1, 2, 2
13:26 Robinlemon it would be 1 1 2
13:26 Robinlemon get it
13:26 kakashiAL you have the numbers 1, 2 and 4, correct?
13:28 Robinlemon yes
13:28 Robinlemon For example sake
13:29 Robinlemon It should work with anything tho
13:29 Robinlemon The target will always be reachable with the numbers
13:29 kakashiAL okay, now you want to get this, with 1, 2 and 4:
13:29 kakashiAL 1, 1, 1
13:29 kakashiAL 2, 2, 2
13:29 kakashiAL 4, 4, 4
13:29 kakashiAL 1, 2, 4
13:29 kakashiAL 1, 1, 2
13:29 Robinlemon No
13:29 Robinlemon 1, 1, 1, 1
13:29 Robinlemon 2, 2
13:29 Robinlemon 4
13:30 Robinlemon The numbers need to add to 4
13:30 Robinlemon I wnat the combinations that add to 4
13:30 kakashiAL ahh if you have 6 you would have this:
13:30 kakashiAL 1, 1, 1, 1, 1, 1
13:30 kakashiAL 2, 2, 2
13:30 Robinlemon Yes
感谢您的阅读,我期待着您的回复!
答案 0 :(得分:1)
您可以使用带有退出条件的递归方法来检查总和或索引。
否则取实际元素并将其连接到临时对象并再次调用该函数,而不增加索引。
另一个方向是使用递增的索引再次调用该函数。
function getCombinations(array, sum) {
function fork(i, t) {
var s = t.reduce(function (a, b) { return a + b; }, 0);
if (sum === s) {
result.push(t);
return;
}
if (s > sum || i === array.length) {
return;
}
fork(i, t.concat([array[i]]));
fork(i + 1, t);
}
var result = [];
fork(0, []);
return result;
}
console.log(getCombinations([1, 2, 4], 4));
console.log(getCombinations([0.11, 0.33, 1], 26.66));
console.log(getCombinations([0.11, 0.33, 1], 23.33));
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
单次使用数字
function getCombinations(array, sum) {
function fork(i, t) {
var s = t.reduce(function (a, b) { return a + b; }, 0);
if (sum === s) {
result.push(t);
return;
}
if (s > sum || i === array.length) {
return;
}
fork(i + 1, t.concat([array[i]]));
fork(i + 1, t);
}
var result = [];
fork(0, []);
return result;
}
console.log(getCombinations([1, 2, 4], 4));
console.log(getCombinations([0.11, 0.33, 1], 26.66));
console.log(getCombinations([0.11, 0.33, 1], 23.33));
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
答案 1 :(得分:1)
这是一个典型的动态编程案例问题,与其他方法相比,它最有可能成为一种更有效的解决方法。这是一个非递归动态编程解决方案。
function getCombos(a,t){
var h = {},
len = a.length,
n = 0;
for (var i = 0; i < len; i++){
n = a[i];
h[n] ? h[n].push([n]) : h[n] = [[n]];
for(var j = a[0]; j <= t; j++){
h[j] && (h[j+n] = h[j+n] ? h[j+n].concat(h[j].map(s => s.concat(n)))
: h[j].map(s => s.concat(n)));
}
}
return h[t] || [];
}
var result = [];
console.time("dp for [1,2,4] to sum 4");
result = getCombos([1,2,4],4);
console.timeEnd("dp for [1,2,4] to sum 4");
console.log(JSON.stringify(result));
console.time("dp for [1,5,9] to sum 500");
result = getCombos([1,5,9],500);
console.timeEnd("dp for [1,5,9] to sum 500");
console.log("There are", result.length, "solutions");
&#13;
根据你的第二个要求。在不重复项目的情况下达到目标也可以通过上面的代码完成,但是效率非常低。
例如给予[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
并要求数字给出总和210(所有数字的总和)需要花费一些时间才能使浏览器崩溃。
通过非重复使用数组项来达到目标总和的正确方法如下:
function getSummingItems(a,t){
return a.reduce((h,n) => Object.keys(h)
.reduceRight((m,k) => +k+n <= t ? (m[+k+n] = m[+k+n] ? m[+k+n].concat(m[k].map(sa => sa.concat(n)))
: m[k].map(sa => sa.concat(n)),m)
: m, h), {0:[[]]})[t];
}
var arr = Array(20).fill().map((_,i) => i+1),
tgt = 210,
res = [];
console.time("test");
res = getSummingItems(arr,tgt);
console.timeEnd("test");
console.log(res);
&#13;
它将在不到1秒的时间内完成上述计算。为了提高性能,可以将.reduce()
和.reduceRight()
替换为命令式等效项。除此之外,这和我一样快。