【问题标题】:Find a subset of a list of given size that sums to target value查找总和为目标值的给定大小列表的子集
【发布时间】:2016-04-20 18:49:40
【问题描述】:

我参加了一个编码测试,其中一个问题是:给定一个由任意长度的整数组成的数组 A,然后是两个数字 N 和 Z,说 A 中是否有 Z(不同)数字,例如它们的总和是N.

例如(格式为 A N Z):

  • [1,2,3] 5 2 的答案是肯定的,因为 2+3=5
  • [1,2,3] 6 2 的答案是否定的,因为 A 中没有两个数字可以相加得到 6

我的解决方案(如下)首先枚举 A 中 Z 数的每个(无序)组合,然后对其求和,然后在总和列表中搜索 N。

虽然这个解决方案运行良好(通过了所有测试用例,没有超时),但我被告知分数太低,无法继续测试。

那么问题来了,有什么可以改进的呢?

一个明显的优化是立即计算每个组合的总和,然后在找到与 N 匹配时停止;但由于我没有遇到时间问题,我认为这不是问题所在。什么是更好、更优雅/高效的解决方案?

function main(a, n, z) {
    var spacea = [], // array of unordered combinations of z integers from a
        space = [], // array of unique sums of combinations from spacea
        res=0; // result (1 or 0)

    // produce combination
    spacea = combo(a,z);

    // put unique sums in space
    spacea.forEach(function(arr) {
        var s = arr.reduce(function(a,b) {
            return a+b;
            });
        if (space.indexOf(s)<0) space.push(s);
        });

    // is n in space?
    res = space.indexOf(n) === -1 ? "NO" :"YES";
    return res;
    }

// produces combinations (outputs array of arrays)                
function combo(a, z) {
    var i,
        r = [],
        head,
        right;
    if (z > a.length || z <= 0) {
        // do nothing, r is already set to []
        }
    else if (a.length === z) {
        r = [a];
        }
    else if (1 === z) {
        // r = array of array of values from a
        a.forEach(function(e) {
            r.push([e]);
            });
        }
    else { // by virtue of above tests, z>1 and z<a.length
        for (i=0; i<a.length-z+1; i++) {
            head = a.slice(i, i+1);
            right = combo(a.slice(i+1), z-1);
            right.forEach(function(e) {
                r.push(head.concat(e));
                });
            }
        }
    return r;
    }

【问题讨论】:

  • 如有必要,请纠正我,但似乎可能的比较组合的数量为 L^Z - LZ + L,其中 L 是 A.length。这是因为 Z 决定了您将获取 A 中的每个值并将其与其他每个值进行比较的次数 -- minus 每次遇到 基于 L 的后续组合。换句话说,对于 [1,2,3] N 3,您只会比较 i=0、j=1 和 k=2——因为迭代 i any由于 离散 组合的要求,进一步将是多余的。另外,请注意 Z=0 和 Z>A.length 是“否”。

标签: javascript algorithm combinations combinatorics


【解决方案1】:

这是subset sum problem 的变体,可以使用Dynamic Programming 解决,以获得更有效的解决方案。

这里的主要区别是您有一个额外的限制 - 必须使用的元素数量。这个额外的限制可以通过添加另一个变量(维度)来处理 - 已使用元素的数量。

递归公式(您将从中构建 DP 解决方案)应该是:

D(0,0,0) = true
D(i,k,x) = false    if i < 0 or k < 0
D(i,k,x) = D(i-1, k, x) OR D(i-1, k-1, x - arr[i])

在上面,D(i,k,x) 为真当且仅当有一个解决方案使用 k 恰好是 k 数字,从第一个 i 元素开始,总和为 x

此解决方案的复杂性是O(n*N*Z),其中n - 数组中的元素数量,N - 可以使用的不同元素数量,Z - 目标总和。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-29
    • 2021-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-07
    • 2016-04-12
    • 1970-01-01
    相关资源
    最近更新 更多