如何创建排列以达到目标数字,但重用提供的数字?

时间:2017-04-03 12:32:03

标签: javascript math recursion integer

修改

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

感谢您的阅读,我期待着您的回复!

2 个答案:

答案 0 :(得分:1)

您可以使用带有退出条件的递归方法来检查总和或索引。

否则取实际元素并将其连接到临时对象并再次调用该函数,而不增加索引。

另一个方向是使用递增的索引再次调用该函数。

&#13;
&#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, 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;
&#13;
&#13;

单次使用数字

&#13;
&#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;
&#13;
&#13;

答案 1 :(得分:1)

这是一个典型的动态编程案例问题,与其他方法相比,它最有可能成为一种更有效的解决方法。这是一个非递归动态编程解决方案。

&#13;
&#13;
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;
&#13;
&#13;

根据你的第二个要求。在不重复项目的情况下达到目标也可以通过上面的代码完成,但是效率非常低。

例如给予[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]并要求数字给出总和210(所有数字的总和)需要花费一些时间才能使浏览器崩溃。

通过非重复使用数组项来达到目标​​总和的正确方法如下:

&#13;
&#13;
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;
&#13;
&#13;

它将在不到1秒的时间内完成上述计算。为了提高性能,可以将.reduce().reduceRight()替换为命令式等效项。除此之外,这和我一样快。