前端算法(53)

46 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

题目

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