给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
示例:
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
解题思路:深度优先+回溯算法
java代码:
class Solution {
public List> combine(int n, int k) {
List> res = new LinkedList<>();
boolean[] f = new boolean[n];
List tmp = new ArrayList<>(k);
dfs(k, 0, n, f, tmp, res);
return res;
}
private void dfs(int left, int s, int n, boolean[] f, List tmp, List> res) {
if(0 == left) {
res.add(tmp);
return;
}
for(int i = s; i < n; i++) {
if(f[i])
continue;
f[i] = true;
List t = new ArrayList<>(tmp);
t.add(i+1);
dfs(left-1, i+1, n, f, t, res);
f[i] = false;
}
}
}
注:由于List是指针传递,所以每次深度搜索的时候,都需要将存放结果子集的list(即tmp)复制一份出来,但是这样效率很低,上述代码的运行时间在150+ms。
对上述代码进行优化,每次深度搜索的时候不再copy一份存放结果子集的list(即tmp),而是当判断tmp为某一个结果子集的时候,再copy一份tmp存放到结果集中,代码如下:
class Solution {
public List> combine(int n, int k) {
List> res = new LinkedList<>();
boolean[] f = new boolean[n];
List tmp = new ArrayList<>(k);
dfs(k, 0, n, f, tmp, res);
return res;
}
private void dfs(int left, int s, int n, boolean[] f, List tmp, List> res) {
if(0 == left) {
res.add(new ArrayList<>(tmp));
return;
}
for(int i = s; i < n; i++) {
if(f[i])
continue;
f[i] = true;
tmp.add(i+1);
dfs(left-1, i+1, n, f, tmp, res);
f[i] = false;
tmp.remove(tmp.size()-1);
}
}
}
运行时间在25ms左右