LeetCode 77 Combinations (Tag:Array Difficulty:Medium)

185 阅读1分钟

这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

前言

关于 LeetCode 数组类型题目的相关解法,可见LeetCode 数组类型题目做前必看,分类别解法总结了题目,可以用来单项提高。觉得有帮助的话,记得多多点赞关注哦,感谢!

题目描述

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

链接:leetcode-cn.com/problems/co…

题解

这道题是典型的组合模版题。我们可以先看一个组合数的模版代码

const Combination = (nums: number[], d: number, n: number, s: number, curr: number[], ans: number[][]) {
    if (d === n) {
        ans.push([...curr])
    }
    for (let i = s; i < nums.lenght; ++i) {
        curr.push(nums[i])
        Combination(nums, d + 1, n, i + 1, curr, ans)
        curr.pop()
    }
}

上述代码中,参数 nums 表示原数组,在这道题目中就是范围[1, n], d 当前组合 curr 的长度, n 代表要求的组合数的长度,对应这道题就是 k, s 代表遍历的起点,随着递归深度加深,起点也往后移,curr 表示当前的组合出来的组合, ans 表示最后的答案。
递归出口是 当 curr 的长度 d 等于 k 时,说明已经找到了一个答案,可以 push 进 ans 的数组。

将本题的条件套上上面的模版后,代码如下

/**
 * @param {number} n
 * @param {number} k
 * @return {number[][]}
 */
var combine = function(n, k) {
    let ans = []
    let curr = []
    let nums = [...Array(n+1).keys()].slice(1)
    Combination(nums, 0, k, 0, curr, ans)
    return ans
};

var Combination = (nums, d, k, s, curr, ans) => {
        if (d === k) {
            ans.push([...curr])
        }
        
        for (let i = s; i < nums.length; i++) {
            if (nums.length  - s  < k - d ) return // 剪枝操作
            curr.push(nums[i])
            Combination(nums, d+1, k, i+1, curr, ans)
            curr.pop()
        }
}

上面解法有一个优化的地方,当递归到下标s时,如果s到n之间的数,已经不能填满剩余的空位时,就没有必要再递归下去了,可以直接退出这次递归。也就是是备注了剪枝操作那一行。