我进入了编码测试,其中一个问题是:给定一个任意长度的整数数组A,然后是两个数字N和Z,说明A中是否有Z(不同)数字,例如它们的总和是ñ
例如(格式为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;
}
答案 0 :(得分:2)
这是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
- 目标总和。