题目描述
给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。
示例:
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combinations
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
构建二叉树+DFS
public class Solution {
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> results = new ArrayList<>();
// 排除特殊情况
if (k <= 0 || n < k) {
return results;
}
// 用来存储每一个生成的数
Deque<Integer> number = new ArrayDeque<>();
dfs(n, k, 1, results, number);
return results;
}
private void dfs(int n, int k, int begin, List<List<Integer>> results, Deque<Integer> number) {
// 递归终止条件:长度到达k
if(number.size() == k) {
results.add(new ArrayList<>(number));
return;
}
//因为题目不要求顺序[1,2] 和[2,1]是一样的
for(int i = begin; i < n+1; i++){
number.addLast(i);
//递归添加后面的数字,一直到长度是k为止
dfs(n, k, i+1, results, number);
// 比如产生[1,2][1,3][1,4]的情况下 1是公用的 但是2,3,4在其他递归中需要移除
number.removeLast();
}
}
}
构建二叉树+DFS+剪枝优化
public class Solution {
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> results = new ArrayList<>();
// 排除特殊情况
if (k <= 0 || n < k) {
return results;
}
// 用来存储每一个生成的数
Deque<Integer> number = new ArrayDeque<>();
dfs(n, k, 1, results, number);
return results;
}
private void dfs(int n, int k, int begin, List<List<Integer>> results, Deque<Integer> number) {
// 递归终止条件:长度到达k
if(number.size() == k) {
results.add(new ArrayList<>(number));
return;
}
//因为题目不要求顺序[1,2] 和[2,1]是一样的
for(int i = begin; i < n -(k-number.size())+2; i++){
number.addLast(i);
//递归添加后面的数字,一直到长度是k为止
dfs(n, k, i+1, results, number);
// 比如产生[1,2][1,3][1,4]的情况下 1是公用的 但是2,3,4在其他递归中需要移除
number.removeLast();
}
}
}
构建二叉树+DFS+剪枝优化(另一种思路)
跟之前不一样的是 递归的标志变成了是不是选这个数
public class Solution {
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> res = new ArrayList<>();
if (k <= 0 || n < k) {
return res;
}
// 为了防止底层动态数组扩容,初始化的时候传入最大长度
Deque<Integer> path = new ArrayDeque<>(k);
dfs(1, n, k, path, res);
return res;
}
private void dfs(int begin, int n, int k, Deque<Integer> path, List<List<Integer>> res) {
if (k == 0) {
res.add(new ArrayList<>(path));
return;
}
// 基础版本的递归终止条件:if (begin == n + 1) {
if (begin > n - k + 1) {
return;
}
// 不选当前考虑的数 begin,直接递归到下一层
dfs(begin + 1, n, k, path, res);
// 不选当前考虑的数 begin,递归到下一层的时候 k - 1,这里 k 表示还需要选多少个数
path.addLast(begin);
dfs(begin + 1, n, k - 1, path, res);
// 深度优先遍历有回头的过程,因此需要撤销选择
path.removeLast();
}
}
迭代
public class Solution {
// 例如n=4,k=2 思路是从1开始[[1,2],[1,3],[1,4],[1,5]
// 发现越界变成[2,3],[2,4],[2,5]
// 越界调整为[3,4]
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> ans = new ArrayList<>();
List<Integer> number = new ArrayList<>();
// 给temp初始化k个0(占位)
for(int i = 0;i<k;i++){
number.add(0);
}
// 0到k-1 对第i位进行叠加处理
// -1代表结束迭代的循环
int i = 0;
while (i >= 0) {
number.set(i, number.get(i)+ 1);
//当前数字大于 n,回到上一位数字 让他继续增大1
if (number.get(i) > n) {
i--;
// 最后一位也已经被赋值了
} else if (i == k - 1) {
ans.add(new ArrayList<>(number));
//开始更新i位后面一位的数字
}else {
i++;
//让后一位的值等于现在第i位的值
number.set(i, number.get(i-1));
}
}
return ans;
}
}
动态规划
https://blog.csdn.net/wind_liang/article/details/104472769?utm_medium=distribute.pc_relevant_t0.none-task-blog-OPENSEARCH-1.nonecase&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-OPENSEARCH-1.nonecase