文章目录
零、原题链接
一、题目描述
给定两个整数 n
和 k
,返回范围 [1, n]
中所有可能的 k
个数的组合。
你可以按 任何顺序 返回答案。
二、测试用例
示例 1:
cpp
输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
示例 2:
cpp
输入:n = 1, k = 1
输出:[[1]]
提示:
cpp
1 <= n <= 20
1 <= k <= n
三、解题思路
- 基本思路:
回溯法 + 剪枝。
为了保证不重复,我们只需要保证每个序列都是递增,所以序列的每个位置取值都有范围,第 i 个数的取值范围为[i,n-k+i]
- 具体思路:
- 回溯:
- 如果该元素超出该位置的范围,则返回。【剪枝】
- 序列 vec 添加该元素。
- 如果是最后一个元素,则将序列 vec 添加到 ans 并弹出最后一个元素。
- 递归遍历下一个位置的元素。
- 弹出最后一个元素【回溯要恢复状态】
- 回溯:
四、参考代码
时间复杂度: O ( k ⋅ C n k ) \Omicron(k\cdot C_n^k) O(k⋅Cnk) 【一共 C n k C_n^k Cnk 的序列,每个序列 k 个元素】
空间复杂度: O ( k ) \Omicron(k) O(k) 【递归栈最深为 k 】
cpp
class Solution {
public:
vector<vector<int>> ans;
vector<int> vec;
int _n;
void dfs(const int& i, const int& k) {
if (i > _n - k + 1)
return;
vec.emplace_back(i);
if (k == 1) {
ans.emplace_back(vec);
vec.pop_back();
return;
}
for (int j = i + 1; j <= _n; j++) {
dfs(j, k - 1);
}
vec.pop_back();
}
vector<vector<int>> combine(int n, int k) {
_n = n;
int t = n - k + 1;
for (int i = 1; i <= t; i++)
dfs(i, k);
return ans;
}
};