方法1: 我自己的方法,我觉得应该也能算dp。就是找规律,找C(n,k)和C(n,k-1)的关系。这道题目的时间空间复杂我就不分析了,脑瓜疼。然后这个方法可以有一个小优化,就是C(n,k) = C(n,n-k)有很大的关系,所以每当k > n/2是,我们就可以套用这个公式减轻运算量。
class Solution {
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> res = new ArrayList<>();
if(k == 0){
res.add(new ArrayList<>());
return res;
}
if(k == 1){
for(int i = 1; i <= n; i++){
List<Integer> curr = new ArrayList<>();
curr.add(i);
res.add(curr);
}
return res;
}
if(k > n / 2){
List<List<Integer>> list = combine(n, n-k);
for(List<Integer> l : list){
List<Integer> hh = new ArrayList<>();
Set<Integer> set = new HashSet<>(l);
for(int i = 1; i <= n; i++){
if(!set.contains(i)) hh.add(i);
}
res.add(hh);
}
return res;
}
List<List<Integer>> list = combine(n, k-1);
for(List<Integer> l : list){
int last = l.get(l.size()-1);
List<Integer> temp = new ArrayList<>(l);
for(int i = last + 1; i <= n; i++){
temp.add(i);
res.add(temp);
temp = new ArrayList<>(l);
}
}
return res;
}
}
方法2: dp。这是discussion部分一个比较好的答案。附上链接。
public class Solution {
public List<List<Integer>> combine(int n, int k) {
if (k == n || k == 0) {
List<Integer> row = new LinkedList<>();
for (int i = 1; i <= k; ++i) {
row.add(i);
}
return new LinkedList<>(Arrays.asList(row));
}
List<List<Integer>> result = this.combine(n - 1, k - 1);
result.forEach(e -> e.add(n));
result.addAll(this.combine(n - 1, k));
return result;
}
}
方法3: lc官方解答1,backtracking。这仿佛和78题一样,我怀疑这个backtracking是一个公式,对于这类题型来说。
class Solution {
List<List<Integer>> output = new LinkedList();
int n;
int k;
public void backtrack(int first, LinkedList<Integer> curr) {
// if the combination is done
if (curr.size() == k)
output.add(new LinkedList(curr));
for (int i = first; i < n + 1; ++i) {
// add i into the current combination
curr.add(i);
// use next integers to complete the combination
backtrack(i + 1, curr);
// backtrack
curr.removeLast();
}
}
public List<List<Integer>> combine(int n, int k) {
this.n = n;
this.k = k;
backtrack(1, new LinkedList<Integer>());
return output;
}
}
总结:
- 无