题目
77. 组合
给定两个整数 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]]
思路
求k个数的组合,每次选一个数字,然后在剩余数组中,再选一个,然后直到选到了k个数字,就本次收集完毕,然后开始回退,接着遍历下一个数字,直到遍历完。
回溯三步曲:
- 递归函数返回值和参数:无返回值,但需要全局变量存放结果,以及当前遍历路径
- 递归终止条件:当path的长度等于k的时候,说明找到了一条路径,将当前path放到result结果里
- 单层递归逻辑:遍历数组,每次push当前元素到path中,然后递归从后面数组中选一个元素,需要几个元素,会深度递归几层,是用递归来模拟了暴力解法的k个循环。
var combine = function(n, k) {
let path = [];
let result = [];
const backTracking = function(n, k, startIndex) {
if (path.length === k) {
// 这里注意要拷贝,否则最后都指向了path一个引用,会出现不对的情况
result.push(path.slice(0));
return;
}
for (let i = startIndex; i < n; i++) {
path.push(i+1)
backTracking(n, k, i + 1);
path.pop();
}
}
backTracking(n, k, 0);
return result;
};
然后,剪枝,这里面当遍历数组时,剩下的元素不足k-path.length时,无需再继续遍历,所以可以把循环条件优化一下,如下:
var combine = function(n, k) {
let path = [];
let result = [];
const backTracking = function(n, k, startIndex) {
if (path.length === k) {
result.push(path.slice(0));
return;
}
// 这里的终止条件缩小了,省去了一些操作
for (let i = startIndex; i < n - (k - path.length) + 1; i++) {
path.push(i+1)
backTracking(n, k, i + 1);
path.pop();
}
}
backTracking(n, k, 0);
return result;
};
总结
写的时候发现,当你看了视频后,你觉得你懂了,但是当你写的时候,好像不对,没写出来,然后写出来后,如果你要写一个文章总结下,发现,咦,好像还是有地方理解错了,学习就是不断的扣细节,不断加深,不断熟练的过程呀。
ps:今天终于写了一道题了,可以打卡了==,哭死,上周忙的无精打采,在gq写代码就是谁都觉得不重要,而且就不需要多久就可以开发完,真是奇怪了,在互联网公司代码那么重要的资产,程序员就是核心,可是在gq,完全就不一样了,我想了想,还是跟企业性质不同,差别太大导致,所以互联网run gq,除非不想搞技术了,否则就别来,你会难受每一天。