【发布时间】: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