前言
我们经常会看到这种需求,从给定的物品列表中找到总价正好是100元的组合。每种组合的元素个数不固定,那么就不能使用暴力遍历的方式了。 举个例子:
从[1, 3, 2, 5, 4, 6] 中找到和为10的组合
我们试图找一下
对顺序没有要求的话,可以找到如下几种组合:[1, 3, 6]、[1, 3, 2, 4]、[1, 4, 5]、[3, 2, 5]、[4, 6],这5种组合包含2、3、4个元素。
分析
可不可以使用递归来做呢? 我们分析一下,对于一个元素A,每一种组合包含两种情况,即组合包含A和组合不包含A。
对于包含A的情况,如果去掉A,那么问题就变成了从剩下的数组中找到和为M - A的组合。这样可以使用递归。
对于不包含A的情况,如果去掉A,那么对结果没有影响,这样依旧可以使用递归。
代码实现
经过分析,我们可以使用如下方法:
let a = []
function findNumber(sum, numberArray, orderIndex) {
if (orderIndex < 0 || sum <= 0) {
return
}
if (sum === numberArray[orderIndex]) {
a.push(sum)
console.log(a.join('-'))
a.pop()
}
a.push(numberArray[orderIndex])
findNumber(sum - numberArray[orderIndex], numberArray, orderIndex - 1)
a.pop()
findNumber(sum, numberArray, orderIndex - 1)
}
/// 测试用例
const b = [1, 3, 2, 5, 4, 6]
findNumber(10, b, b.length - 1)
// 6-4
// 6-3-1
// 4-5-1
// 4-2-3-1
// 5-2-3
总结
使用递归实现,代码够整洁。但是这个递归比较特殊,所有的结果都引用了a这个变量。在使用某个组合的时候不要修改a数组。当然还有其他的方式,欢迎讨论。