持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第27天,点击查看活动详情
77.组合
题目分析
题目给出两个整数n和k,要求返回范围,1到n中,所有可能的k个数的组合。例如
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
解题
看到这道题大家可能想使用暴力的方法解决。如果k等于2的话,可以使用两层for循环解决问题。但是当k变得很大的时候,循环的嵌套就十分恐怖了,所以这种方式不成立。
本题是回溯法的一个经典题目,我们可以通过回溯法解决。前面回溯法中说到可以将回溯解决的问题想象为树形结构,组合问题就可以这样抽象。
上图可以看出我们首先在一二三四中取一个数字,下一次去就在二三四中取一个数,依次向下进行,就可以得到想要的集合(叶子节点)。那么范围n就可以看作是树的宽度,k相当于树的深度。
接下来进行回溯三部曲:
- 递归函数的返回值和参数
函数的参数首先是集合n,其次是k,还需要一个变量用于记录集合从哪里开始遍历。
- 回溯函数终止条件
终止条件是当遍历到叶子节点就可以存到结果数组中。
- 单层搜索的过程
单层循环就是向右横向遍历通过for循环,并且通过递归纵向遍历。
代码如下:
let result = []
let path = []
var combine = function(n, k) {
result = []
backtracking(n,k,1)
return result
};
const backtracking = (n,k,startIndex) => {
if(path.length === k) {
result.push([...path])
return
}
for(let i = startIndex;i <= n - (k - path.length) + 1;++i) {
path.push(i)
backtracking(n,k,i + 1)
path.pop()
}
}
在上面的代码中,我们定义了一个path变量,用于记录递归过程中的数,当path的长度等于k时,证明已经递归到了叶子节点,可以将path存入结果数组中。
同时可以看到for循环中对i的限制,上面的代码已经做了剪枝操作。因为就像最上面的那个图,当取4的时候不再有结果,因为已经没有K个值可取。