这是我参与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之间的数,已经不能填满剩余的空位时,就没有必要再递归下去了,可以直接退出这次递归。也就是是备注了剪枝操作那一行。