这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战
题目
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
示例
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
输入: n = 1, k = 1
输出: [[1]]
提示
1 <= n <= 201 <= k <= n
解题思路
回溯
如果解决一个问题有多个步骤,每个步骤有多种方法,又需要求得所有的方法,那么就可以使用回溯算法。
如本题,要求得[1,n]区间内所有由k个数组成的子数组集合,我们可以将其转换成一个多叉树,再通过穷举,得到所有的子数组。
图形画出来了,根据图中总结出的步骤,我们可以发现如下结构:
- 获取当前数值,再从后续区间找多一个数值进行组合;
- 排除前面已统计过的数值。
以此类推,可体现出递归结构。
由于需要统计路径上的多个节点,因此我们需要一个存储的变量l用来记录节点信息,该变量采用LinkedList类型来保存节点信息,便于我们对其进行添加删除节点,使其可以复用。
class Solution {
private List<List<Integer>> list;
public List<List<Integer>> combine(int n, int k) {
this.list = new ArrayList<>();
if(k == 0) return list;
// 回溯入口
backtracking(n, k, new LinkedList());
// 返回结果
return list;
}
/**
* 回溯
* @param n 区间
* @param k 子数组长度
* @param l 保存路径上的节点
*/
public void backtracking(int n, int k, LinkedList<Integer> l){
// 边界判断
if(n < k - l.size() - 1){return;}
// 添加子数组到集合中
if(l.size() == k){
list.add(new ArrayList(l));
return;
}
// 遍历后续元素
for(int i = n; i > 0; --i){
// 添加元素为头节点
l.addFirst(i);
// 递归,添加后续节点
backtracking(i - 1, k, l);
// 删除头节点,返回最初始初始状态,进入下一轮
l.removeFirst();
}
}
}
复杂度分析
- 时间复杂度:
- 空间复杂度:
最后
文章有写的不好的地方,请大佬们不吝赐教,错误是最能让人成长的,愿我与大佬间的距离逐渐缩短!
如果觉得文章对你有帮助,请 点赞、收藏、关注、评论 一键四连支持,你的支持就是我创作最大的动力!!!