题目描述
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
示例 1:
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
示例 2:
输入: n = 1, k = 1
输出: [[1]]
思路
回溯三部曲:
- 确定参数和返回值
- 确定终止条件
- 确定单层递归逻辑
- 本题的参数:n(范围[1,n]),k(个数),startIndex(遍历开始的位置)
- 终止条件:取数的个数为k时
- 单层递归逻辑:遍历里面嵌套递归(注意回溯!)
代码
function combine(n: number, k: number): number[][] {
let result=[],path=[];
function blackTracking(n: number, k: number,startIndex:number):void{
if(path.length==k){
result.push([...path]);
return;
}
for(let i=startIndex;i<n;i++){
path.push(i+1);
blackTracking(n,k,i+1);
path.pop(); //回溯操作
}
}
blackTracking(n,k,0);
return result
};
减枝操作
思路:剩下的可选的数>=需要的数即n-i>=k-path.length得到i<=n-k+path.length
function combine(n: number, k: number): number[][] {
let result=[],path=[];
function blackTracking(n: number, k: number,startIndex:number):void{
if(path.length==k){
result.push([...path]);
return;
}
//剪枝操作
for(let i=startIndex;i<=n-k+path.length;i++){
path.push(i+1);
blackTracking(n,k,i+1);
path.pop(); //回溯操作
}
}
blackTracking(n,k,0);
return result
};
总结
对于回溯(backtracking)问题(组合,分割,子集,排列,棋盘等问题)都可以抽象为树形结构,集合的大小就构成了树的宽度,递归的深度构成的树的深度。