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 }
当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 }
法二(借鉴):做完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 }