组合

115 阅读1分钟

题目描述

给定两个整数 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]]

思路

image.png

回溯三部曲:

  1. 确定参数和返回值
  2. 确定终止条件
  3. 确定单层递归逻辑
  • 本题的参数: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

};

image.png

减枝操作

思路:剩下的可选的数>=需要的数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)问题(组合,分割,子集,排列,棋盘等问题)都可以抽象为树形结构集合的大小就构成了树的宽度,递归的深度构成的树的深度image.png