1. 题目链接:77. 组合
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. 解法(回溯):
3.1 算法思路:
题目要求我们从1到n中选择k个数的所有组合,其中不考虑顺序。也就是说[1,2]和[2,1]等价。我们s需要找出所有的组合,但不能重复计算相同元素的不同顺序的组合。对于选择组合,我们需要进行以下流程:
- 所有元素分别作为首位元素进行处理
- 在之后的位置上同理,选择所有元素分别作为当前位置元素进行处理
- 为避免计算重复组合,规定选择之后位置的元素时必须比前一个元素大,这样就不会有重复的组合
3.2 实现方法:
- 定义一个二维数组和一个一维数组。二维数组用来记录所有组合,一维数组用来记录当前状态下的组合
- 遍历1到n-k+1,以当前数作为组合的首位元素进行递归(从n-k+1到n作为首元素时,组合中一定不会存在k个元素)
- 递归函数的参数为两个数组、当前步骤以及n和k,递归流程如下:
- 结束条件:当前组合中已经有k个元素,将当前组合存进二维数组并返回(剪枝:如果当前位置之后的所有元素放入组合也不能满足组合中存在k个元素,直接返回)
- 从当前位置的下一个元素开始遍历到n,将元素赋值到当前位置,递归下一个位置
3.3 C++算法代码:
class Solution {vector<int> path; // 用于存储当前路径的数组vector<vector<int>> ret; // 用于存储所有满足条件的路径的二维数组int n, k; // n表示元素个数,k表示每个组合中的元素个数public:vector<vector<int>> combine(int _n, int _k) {n = _n; // 初始化元素个数k = _k; // 初始化每个组合中的元素个数dfs(1); // 从第一个元素开始进行深度优先搜索return ret; // 返回所有满足条件的路径}void dfs(int start) {if (path.size() == k) { // 如果当前路径的长度等于k,说明找到了一个满足条件的路径ret.push_back(path); // 将当前路径添加到结果集中return;}for (int i = start; i <= n; i++) { // 从start开始遍历到npath.push_back(i); // 将当前元素添加到路径中dfs(i + 1); // 继续搜索下一个元素path.pop_back(); // 回溯,将当前元素从路径中移除}}
};