77.Combinations

题目链接:https://leetcode.com/problems/combinations/description/

题目大意:组合问题,给出一个数n以及要组合的数的个数k,输出所有组合数。

法一(借鉴):虽然前面做了排列的题,可惜还是不会做这个组合题。代码如下(耗时76ms):

 1     public List<List<Integer>> combine(int n, int k) {
 2         List<List<Integer>> res = new ArrayList<List<Integer>>();
 3         List<Integer> tmp = new ArrayList<Integer>();
 4         dfs(res, tmp, n, k, 1);
 5         return res;
 6     }
 7     public static void dfs(List<List<Integer>> res, List<Integer> tmp, int n, int k, int start) {
 8     //    System.out.println(tmp);
 9         if(tmp.size() == k) {
10             res.add(new ArrayList<Integer>(tmp));
11             return;
12         }
13         for(int i = start; i <= n; i++) {
14             tmp.add(i);
15             dfs(res, tmp, n, k, i + 1);
16             tmp.remove(tmp.size() - 1);//回溯删除
17         }
18     }
View Code

当n=4,k=2时的运行结果:

[]
[1]
[1, 2]--->return执行i++ -> add
[1, 3]--->return执行i++ -> add
[1, 4]--->return执行i++ -> add
[2]--->return到1dfs后执行remove操作,再i++ -> add
[2, 3]
[2, 4]
[3]
[3, 4]
[4]
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]

优化剪枝:http://blog.csdn.net/wys2011101169/article/details/72887512 

根据这个博客剪枝,原因可见博客。代码如下(耗时4ms):

 1     public List<List<Integer>> combine(int n, int k) {
 2         List<List<Integer>> res = new ArrayList<List<Integer>>();
 3         List<Integer> tmp = new ArrayList<Integer>();
 4         dfs(res, tmp, n, k, 1);
 5         return res;
 6     }
 7     public static void dfs(List<List<Integer>> res, List<Integer> tmp, int n, int k, int start) {
 8         if(tmp.size() == k) {
 9             res.add(new ArrayList<Integer>(tmp));
10             return;
11         }
12         for(int i = start; i <= (n - (k - tmp.size()) + 1); i++) {
13             //i <= (n - (k - tmp.size()) + 1)剪枝,当可选的数已经不够时,直接剪枝
14             tmp.add(i);
15             dfs(res, tmp, n, k, i + 1);
16             tmp.remove(tmp.size() - 1);//回溯删除
17         }
18     }
View Code

法二(借鉴):做完78题,回头用78题的非递归代码,发现超时了,按理说这个办法应该是可以过的,但是应该需要合理的剪枝吧。代码如下:

 1     public List<List<Integer>> combine(int n, int k) {
 2         List<List<Integer>> res = new ArrayList<List<Integer>>();
 3         res.add(new ArrayList<Integer>());
 4         for(int i = 1; i <= n; i++) {
 5             List<List<Integer>> tmp = new ArrayList<List<Integer>>();
 6             for(List<Integer> r : res) {
 7                 List<Integer> a = new ArrayList<Integer>(r);
 8                 a.add(i);
 9                 tmp.add(a);
10             }
11             res.addAll(tmp);
12         }
13         //从所有集合中拿到个数是k的子集合加到结果集中
14         List<List<Integer>> list = new ArrayList<List<Integer>>();
15         for(List<Integer> r : res) {
16             if(r.size() == k) {
17                 list.add(r);
18             }
19         }
20         return list;
21     }
View Code
原文地址:https://www.cnblogs.com/cing/p/7866512.html