题目

给定两个整数 nk,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

示例 1:

1
2
3
4
5
6
7
8
9
10
输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]

示例 2:

1
2
输入:n = 1, k = 1
输出:[[1]]

提示:

  • 1 <= n <= 20
  • 1 <= k <= n

实现代码

使用DFS实现回溯算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {

List<List<Integer>> traceList = new LinkedList<>();
// 记录回溯算法的递归路径
LinkedList<Integer> trace = new LinkedList<>();

public List<List<Integer>> combine(int n, int k) {

traverse(1, n, k);
return traceList;
}

private void traverse(int start, int n, int k) {
if (trace.size() == k) {
traceList.add(new LinkedList<>(trace));
// 不往下找了,直接返回
return;
}
for (int i = start; i <= n; i++) {
trace.addLast(i);
traverse(i + 1, n, k);
trace.removeLast();
}
}
}

时间复杂度

n个元素种找出k个元素的组合,在数学中组合数公式为:C(n, k)

每次traceList.add(new LinkedList<>(trace));的时间为O(k)

所以总的时间复杂度为:O(k*C(n, k ))

空间复杂度

主要的额外空间消耗来自:

  1. traceList:总组合为C(n, k),每个组合k个元素,所以为k*C(n, k)
  2. trace:递归过程中存储当前路径,最大深度为k,空间复杂度为O(k)
  3. 递归调用栈:最大深度为k,空间复杂度为O(k)

因此总的空间复杂度为O(k*C(n, k)),如果不计算输出结果的存储空间,那么额外空间复杂度为O(k)