题目:
Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.
For example,
If n = 4 and k = 2, a solution is:
[ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]Backtracking
链接: http://leetcode.com/problems/combinations/
题解:
求组合数。依然是使用recursive + backtracking,当所传list的大小等于k时,将list加入到result里。使用控制位置的变量pos根据题目要求从1开始,本体依然假定无重复数字。
Time Complexity - O(2n), Space Complexity - O(n)。 --复杂度有点糊涂,还需要重新计算
public class Solution { public ArrayList<ArrayList<Integer>> combine(int n, int k) { ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>(); if(n < 0 || k < 0) return result; ArrayList<Integer> list = new ArrayList<Integer>(); helper(result, list, n, k, 1); return result; } private void helper(ArrayList<ArrayList<Integer>> result, ArrayList<Integer> list, int n, int k, int pos){ if(list.size() == k){ result.add(new ArrayList<Integer>(list)); return; } for(int i = pos; i <= n; i++){ list.add(pos); helper(result, list, n, k, ++pos); list.remove(list.size() - 1); } } }
Update:
public class Solution { public List<List<Integer>> combine(int n, int k) { List<List<Integer>> res = new ArrayList<>(); if(n < 0 || k < 0) return res; ArrayList<Integer> list = new ArrayList<Integer>(); dfs(res, list, n, k, 1); return res; } private void dfs(List<List<Integer>> res, ArrayList<Integer> list, int n, int k, int position) { // from 1 to n if(list.size() == k) { res.add(new ArrayList<Integer>(list)); return; } for(int i = position; i <= n; i++) { list.add(i); dfs(res, list, n, k, i + 1); list.remove(list.size() - 1); } } }
二刷
有关这一类排列组合题目有不少题型,一定要好好思考总结融会贯通。
依然是跟1刷类似的方法,使用DFS + Backtracking。要注意的是最后的结果是(1, 2), (1, 3), (1, 4), (2, 3), (2, 4)这类一定是升序的组合,所以我们构建辅助函数的时候只要pass in 一个position来控制就可以了。递归的时候传入 combine(res, list, k, n, i + 1)这样就能简单避免掉i,只丛i后面的数字继续遍历。
这里branching factor是n, depth是k。 所以其实时间复杂度是 O(n! / k!) 约等于 O(n!)
Time Complexity - O(n!), Space Complexity - O(nk)
Java:
public class Solution { public List<List<Integer>> combine(int n, int k) { List<List<Integer>> res = new ArrayList<>(); List<Integer> list = new ArrayList<>(); combine(res, list, n, k, 1); return res; } private void combine(List<List<Integer>> res, List<Integer> list, int n, int k, int pos) { if (list.size() == k) { res.add(new ArrayList<Integer>(list)); return; } for (int i = pos; i <= n; i++) { list.add(i); combine(res, list, n, k, i + 1); list.remove(list.size() - 1); } } }
三刷:
方法跟二刷一样。也是构造递归求解的辅助方法来解决。注意这里我们也需要一个保存position的int pos。
有机会要再算一算复杂度。
Java:
public class Solution { public List<List<Integer>> combine(int n, int k) { List<List<Integer>> res = new ArrayList<>(); if (n < 0 || k < 0 || n < k) return res; getCombinations(res, new ArrayList<Integer>(), n, k, 1); return res; } private void getCombinations(List<List<Integer>> res, List<Integer> list, int n, int k, int pos) { if (list.size() == k) { res.add(new ArrayList<>(list)); return; } for (int i = pos; i <= n; i++) { list.add(i); getCombinations(res, list, n, k, i + 1); list.remove(list.size() - 1); } } }
Reference:
http://www.1point3acres.com/bbs/thread-117602-1-1.html
http://codeganker.blogspot.com/2014/03/combinations-leetcode.html
http://www.cnblogs.com/zhuli19901106/p/3485751.html
http://www.1point3acres.com/bbs/thread-117602-1-1.html
https://leetcode.com/discuss/42034/java-solution-easy-understood
https://leetcode.com/discuss/30221/dfs-recursive-java-solution
https://leetcode.com/discuss/61607/ac-python-backtracking-iterative-solution-60-ms
https://leetcode.com/discuss/37021/1-liner-3-liner-4-liner
https://leetcode.com/discuss/24600/iterative-java-solution
https://leetcode.com/discuss/12915/my-shortest-c-solution-using-dfs
https://leetcode.com/discuss/31250/backtracking-solution-java
http://rangerway.com/way/algorithm-permutation-combination-subset/
http://www.1point3acres.com/bbs/thread-117602-1-1.html
http://www.cnblogs.com/zhuli19901106/p/3492515.html