本文已参与「新人创作礼」活动,一起开启掘金创作之路。
题目
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
题目解析
思路一
我们以想要的数组长度为判断条件,当长度符合时,就返回上一节点,并执行带走原数组值,跳到下一节点继续执行方法
/**
* @param {number} n
* @param {number} k
* @return {number[][]}
*/
var combine = function(n, k) {
let arr = [];
let temp = [];
if(n == 0 || k == 0){
return arr;
}
//cur:所在位置;temp:选好的数组
function dfs(cur,n,k,temp){
//如果剩余的位置不足以形成最终的正确结果,就返回上一节点
if(temp.length + (n - cur + 1) < k){
return;
}
//记录到最终数组中,并返回上一节点
if(temp.length == k){
arr.push(temp);
return;
}
//在当前位置算入组合则记录当前数,到数组的下一位置,算入一个组合
dfs(cur+1,n,k,[...temp,cur]);
//在当前位置不算入组合则不记录当前数,移到数组下一位置,从下一点开始拿取数组数据
dfs(cur+1,n,k,temp);
}
//开始递归
dfs(1,n,k,temp);
return arr;
};
思路二
我们这里继续使用递归,每次取一个未使用的数字,放到队列,但是这样会有重复,所以我们需要去除重复,则每次取数字都取大于当前值的任一个数字,循环向后遍历每种可能,并cur记录当前,然后每层递归取一个数字放入历史队列,当层数达到k时,保存到res中
/**
* @param {number} n
* @param {number} k
* @return {number[][]}
*/
var combine = function(n, k) {
let res = [];
let dfs = function(his,cur,lev,n,k){
if(lev > k) return;
//如果层数达到,则存储当前序列
if(lev === k){
for(let i = cur; i <= n - (k - lev); i++){
let tmp = his.slice();
tmp.push(i);
res.push(tmp);
}
return;
}
//当前层数不够,则继续下探
for(let j = cur; j <= n - (k - lev); j++){
let tmp = his.slice();
tmp.push(j);
dfs(tmp,j+1,lev+1,n,k);
}
}
//记录历史数||当前可以推进的数字||当前层数||n ||k
dfs([],1,1,n,k);
return res;
};