1.题目链接:
2.题目描述:
给定两个整数 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]]
• 提示:
1 <= n <= 20
1 <= k <= n
3. 解法(回溯):
算法思路:
题目要求我们从 1 到 n 中选择 k 个数的所有组合,其中不考虑顺序。也就是说,[1,2] 和 [2,1] 等价。我们需要找出所有的组合,但不能重复计算相同元素的不同顺序的组合。对于选择组合,我们需要进行如下流程:
1. 所有元素分别作为首位元素进行处理;
2. 在之后的位置上同理,选择所有元素分别作为当前位置元素进行处理;
3. 为避免计算重复组合,规定选择之后位置的元素时必须比前一个元素大,这样就不会有重复的组合([1,2] 和 [2,1] 中 [2,1] 不会出现)。
递归函数设计:void dfs(vector<vector<int>>& ans, vector<int>& v, int step, int &n, int &k)参数:step(当前需要进行处理的位置);
返回值:无;
函数作用:某个元素作为首位元素出现时,查找所有可能的组合。
具体实现方法如下:
1. 定义一个二维数组和一维数组。二维数组用来记录所有组合,一维数组用来记录当前状态下的组 合。
2. 遍历 1 到 n-k+1,以当前数作为组合的首位元素进行递归(从 n-k+1 到 n 作为首位元素时,组合中一定不会存在 k 个元素)。
3. 递归函数的参数为两个数组、当前步骤以及 n 和 k。递归流程如下:
a. 结束条件:当前组合中已经有 k 个元素,将当前组合存进二维数组并返回。
剪枝:如果当前位置之后的所有元素放入组合也不能满足组合中存在 k 个元素,直接返回。▪
b. 从当前位置的下一个元素开始遍历到 n,将元素赋值到当前位置,递归下一个位置。
Java算法代码:
class Solution {
List<Integer> path;
List<List<Integer>> ret;
int n,k;
public List<List<Integer>> combine(int _n, int _k) {
n = _n; k = _k;
path = new ArrayList<>();
ret = new ArrayList<>();
dfs(1);
return ret;
}
public void dfs(int start){
if(path.size() == k) {
ret.add(new ArrayList<>(path));
return ;
}
for (int i = start; i<= n; i++){
path.add(i);
dfs(i + 1);
path.remove(path.size() - 1);
}
}
}
运行结果:
递归展开:
逻辑展开:
上面的一些细节,重点开递归展开一层后,后面的可以直接写出来(经过前面的题目的练习,应该已经可以做到了)。注意我的红字,是一个小细节。
---------------------------------------------------------------------------------------------------------------------------------
记住,相信你的递归函数,它可以做到!
记住,不理解时候,去尝试手动展开!
记住,逻辑展开(你不可能对所有的题目都进行手动展开)!