组合问题
组合问题是指从给定个数的元素中仅仅取出指定个数的元素
- 经典案例
从集合{a, b, c, d, e, f, g}中取出n个元素,有多少种组合实现
- 案例分析
- 假设取出元素为1 则有
种取法, 程序实现的话代码片段如下:
for(let i=0; i<7; i++){
yield S[i]
}
取一个元素,我们使用一个循环,元素一个一个取出来
- 假设要取出2个, 数学公式
- 程序实现可以是我们先取出一个,然后在一个循环从第二个开始取,然后组合起来,片段如下
for(let i=0; i<7; i++){
for(let j=1; i<7; j++){
yield S[i]::S[j] //把结果组合然后返回
}
}
- 假设要取出3个的话我们按照上面思路,可能需要三个嵌套循环
...
如果取出的球个数较多,这种思路理论成立但是很难实现,我们需要寻求更好的方式
- 利用递归解决组合问题(n球,取k个)
- 把问题拆分为更小的子问题
- 子问题的终止条件即最小问题的解, 取出k=0或者取出k=总球数
- 第一种情况先取第一个球,然后在n-1个球中在取k-1个球
- 第二种情况直接在n-1个球中取k个
- 不断递归然后把解合并
- 代码实现
function combination(S, k){
//当设定取值个数为0或者取出k个正好等于S的长度我们返回结果
if(k===0 || S.length===k){
return [ S.slice(0, k) ]
}
//把第一个元素与剩下的元素解构出来
const [first, ...other] = S
//记录每次的结果
let r = []
//先取出一个,然后在剩下元素中取k-1个,把每次取出的都与第一个组合返回
r = r.concat(combination(other, k-1).map(x => [first, ...x]))
//然后在剩下的元素中取出k个
r = r.concat(combination(other, k))
//返回所有结果
return r
}