《代码随想录》Ⅶ 回溯算法-组合 77. 组合
努力学习!
题目:力扣链接
-
给定两个整数
n
和k
,返回范围[1, n]
中所有可能的k
个数的组合。你可以按 任何顺序 返回答案。
一、思想
这道题的核心思想是使用回溯算法来生成所有可能的组合。回溯算法是一种通过递归来探索所有可能解的算法,通常用于解决组合、排列、子集等问题。在这道题中,我们需要从范围 [1, n]
中选择 k
个数的所有可能组合。
具体来说,回溯算法的思路如下:
- 选择:从当前可选的数字中选择一个数字,并将其添加到当前路径中。
- 递归:继续选择下一个数字,直到路径中的数字个数达到
k
。 - 回溯:当路径中的数字个数达到
k
时,将当前路径添加到结果集中,并回溯到上一步,继续选择其他可能的数字。
通过这种方式,我们可以遍历所有可能的组合,并确保每个组合都是唯一的。
二、代码
class Solution
{
public:
/**
* 存放符合条件结果的集合
*/
vector<vector<int>> result;
/**
* 用来存放符合条件结果
*/
vector<int> path;
/**
* 回溯函数,用于生成所有可能的组合
* @param n 数字上限
* @param k 组合元素个数
* @param startIndex 起始索引
*/
void backtracking(int n, int k, int startIndex)
{
// 如果路径长度等于k,说明找到了一个符合条件的组合,将其添加到结果集中
if (path.size() == k) {
result.push_back(path);
return;
}
// 遍历从startIndex到n的所有数字
for (int i = startIndex; i <= n - (k - path.size()) + 1; ++i) {
// 将当前数字添加到路径中
path.push_back(i);
// 递归调用,寻找下一个数字
backtracking(n, k, i + 1);
// 回溯,将当前数字从路径中移除
path.pop_back();
}
}
/**
* 生成所有可能的组合
* @param n 数字上限
* @param k 组合元素个数
* @return 所有可能的组合
*/
vector<vector<int>> combine(int n, int k)
{
// 清空结果集和路径
result.clear();
path.clear();
// 调用回溯函数,生成所有可能的组合
backtracking(n, k, 1);
// 返回结果集
return result;
}
};
三、代码解析
1. 算法工作原理分解
1.1 回溯函数 backtracking
-
目的:递归地生成所有可能的组合。
-
实现:
- 终止条件:当路径中的数字个数等于
k
时,将当前路径添加到结果集中,并返回。 - 选择与递归:从
startIndex
开始遍历所有可能的数字,将当前数字添加到路径中,并递归调用backtracking
函数,继续选择下一个数字。 - 回溯:在递归调用返回后,将当前数字从路径中移除,以便尝试其他可能的数字。
- 终止条件:当路径中的数字个数等于
1.2 组合生成函数 combine
-
目的:初始化并调用回溯函数,生成所有可能的组合。
-
实现:
- 初始化:清空结果集和路径。
- 调用回溯函数:从数字
1
开始,调用backtracking
函数生成所有可能的组合。 - 返回结果:返回生成的所有组合。
2. 关键点说明
2.1 路径的选择与回溯
- 路径:
path
变量用于存储当前正在生成的组合。 - 选择:每次选择一个数字并将其添加到
path
中。 - 回溯:在递归调用返回后,将当前数字从
path
中移除,以便尝试其他可能的数字。
2.2 结果集的存储
- 结果集:
result
变量用于存储所有符合条件的组合。 - 添加条件:当
path
中的数字个数等于k
时,将path
添加到result
中。
2.3 剪枝
- 所以,可以剪枝的地方就在递归中每一层的for循环所选择的起始位置。
- 如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了。
四、复杂度分析
-
时间复杂度:
O(C(n, k))
- 其中
C(n, k)
是从n
个数字中选择k
个数字的组合数。对于每个组合,我们需要O(k)
的时间来生成,因此总时间复杂度为O(C(n, k) * k)
。
- 其中
-
空间复杂度:
O(k)
- 递归调用栈的深度最多为
k
,因此空间复杂度为O(k)
。此外,结果集result
的空间复杂度为O(C(n, k) * k)
,但在通常情况下,我们只考虑递归栈的空间复杂度。
- 递归调用栈的深度最多为
白展堂:人生就是这样,苦和累你总得选一样吧?哪有什么好事都让你一个人占了呢。 ——《武林外传》