Combination/Permutation/Subset
Part I: Combination
- k numbers from 1 to n
public List combine(int n, int k) { List
res = new ArrayList
(); if (n < 1 || k > n) { return res; } combine(n, 1, new ArrayList<Integer>(), k, res); return res; } public void combine(int n, int index, List<Integer> list, int k, List
res) { if (index > n && k != list.size()) { return; } if (k == list.size()) { res.add(new ArrayList<>(list)); return; } for (int i = index; i <= n; i++) { list.add(i); combine(n, i+1, list, k, res); list.remove(list.size()-1); } }
- Combination sum: element can be repeately used
public List combinationSum(int[] candidates, int target) { List
res = new ArrayList
(); if (candidates.length == 0) { return res; } Arrays.sort(candidates); combineSum(candidates, 0, target, new ArrayList<Integer>(), res); return res; } public void combineSum(int[] candidates, int index, int target, List<Integer> curr, List
res) { if (target < 0) { return; } if (target == 0) { res.add(new ArrayList<Integer>(curr)); return; } for (int i = index; i < candidates.length; i++) { if (i > index && candidates[i] == candidates[i-1]) // deal with duplicates continue; curr.add(candidates[i]); combineSum(candidates, i, target-candidates[i], curr, res); curr.remove(curr.size()-1); } }
- Combination sum: element can be used once
public List combinationSum2(int[] candidates, int target) { List
res = new ArrayList
(); if (candidates.length == 0) { return res; } Arrays.sort(candidates); combineSum(candidates, 0, target, new ArrayList<Integer>(), res); return res; } public void combineSum(int[] candidates, int index, int target, List<Integer> curr, List
res) { if (index > candidates.length || target < 0) { return; } if (target == 0) { res.add(new ArrayList<Integer>(curr)); return; } for (int i = index; i < candidates.length; i++) { if (i > index && candidates[i] == candidates[i-1]) continue; curr.add(candidates[i]); combineSum(candidates, i+1, target-candidates[i], curr, res); curr.remove(curr.size()-1); } }
- Factor combinations
public List getFactors(int n) { List
ret = new ArrayList
(); helper(ret, new ArrayList<Integer> (), n, 2); return ret; } private void helper(List
ret, List<Integer> item, int n, int start) { if (n == 1) { if (item.size() > 1) { ret.add(new ArrayList<Integer> (item)); } return; } for (int i = start; i <= n; i++) { if (n % i == 0) { item.add(i); helper(ret, item, n/i, i); item.remove(item.size()-1); } } }
Part II: Subsets
- distinct elements
a. insert element to the previous result
public List subsets(int[] nums) { List
res = new ArrayList
(); res.add(new ArrayList<Integer>()); if (nums.length == 0) { return res; } Arrays.sort(nums); for (int i = 0; i < nums.length; i++) { int num = nums[i]; int size = res.size(); for (int j = 0; j < size; j++) { List<Integer> tlist = new ArrayList<>(res.get(j)); tlist.add(num); res.add(tlist); } } return res; }
b. DFS
public List subsets(int[] S) { List
result = new ArrayList
(); if(S.length == 0){ return result; } Arrays.sort(S); dfs(S, 0, new ArrayList<Integer>(), result); return result; } public void dfs(int[] s, int index, List<Integer> path, List
result){ result.add(new ArrayList<Integer>(path)); for(int i = index; i < s.length; i++){ path.add(s[i]); dfs(s, i+1, path, result); path.remove(path.size()-1); } }
c.bit manipulation
public List subsets(int[] nums) { int n = nums.length; List
subsets = new ArrayList<>(); for (int i = 0; i < Math.pow(2, n); i++) { List<Integer> subset = new ArrayList<>(); for (int j = 0; j < n; j++) { if (((1 << j) & i) != 0) subset.add(nums[j]); } Collections.sort(subset); subsets.add(subset); } return subsets; }
- with duplicate elements
a. when encounter duplicate, add new element only to the right half: see the variable start
public List subsetsWithDup(int[] nums) { List
res = new ArrayList
(); res.add(new ArrayList<Integer>()); if (nums.length == 0) { return res; } Arrays.sort(nums); int start = 0; for (int i = 0; i < nums.length; i++) { int num = nums[i]; int size = res.size(); for (int j = start; j < size; j++) { List<Integer> tlist = new ArrayList<>(res.get(j)); tlist.add(num); res.add(tlist); } start = 0; if (i < nums.length-1 && nums[i] == nums[i+1]) { start = size; } } return res; }
b. check if the list is already in the result each time, less efficient
public List subsetsWithDup(int[] nums) { List
res = new ArrayList
(); res.add(new ArrayList<Integer>()); if (nums.length == 0) { return res; } Arrays.sort(nums); for (int i = 0; i < nums.length; i++) { int num = nums[i]; List
tmp = new ArrayList
(); for (List<Integer> list : res) { List<Integer> tlist = new ArrayList<>(list); tlist.add(num); if (!res.contains(tlist)) tmp.add(tlist); } res.addAll(tmp); } return res; }
Part III: Permutations
- Distinct elements
a. add new element to every possible position of the previous set
public List permute(int[] nums) { List
res = new ArrayList
(); if (nums.length == 0) { return res; } res.add(new ArrayList<Integer>()); for (int i = 0; i < nums.length; i++) { int num = nums[i]; int size = res.size(); List
bak = new ArrayList
(); for (int j = 0; j < size; j++) { List<Integer> list = res.get(j); for (int k = 0; k <= list.size(); k++) { List<Integer> tmp = new ArrayList<>(list); tmp.add(k, num); bak.add(tmp); } //res.remove(j); } res = bak; } return res; }
b. swap every element once to the front and do the same thing for the rest
public List permuteUnique(int[] nums) { List
res = new ArrayList
(); Arrays.sort(nums); LinkedList<Integer> list = new LinkedList<Integer>(); for (int num : nums) list.add(num); permute(list, 0, res); return res; } private void permute(LinkedList<Integer> nums, int start, List
res){ if (start == nums.size() - 1){ res.add(new LinkedList<Integer>(nums)); return; } for (int i = start; i < nums.size(); i++){ if (i > start && nums.get(i) == nums.get(i - 1)) continue; // this deal with duplicates nums.add(start, nums.get(i)); nums.remove(i + 1); permute(nums, start + 1, res); nums.add(i + 1, nums.get(start)); nums.remove(start); } }
- with duplicates: check previous code
- find the kth permutation sequence of number 1 to n
public String getPermutation(int n, int k) { if (n <= 0 || k <= 0) { return new String(); } List<Integer> nums = new ArrayList<>(); int fac = 1; for (int i = 1; i <= n; i++) { fac *= i; nums.add(i); } if (k > fac) { return new String(); } fac /= n; k--; StringBuilder sb = new StringBuilder(); for (int i = 1; i <= n; i++) { int index = k / fac; //if (index > 0) //index--; sb.append(nums.get(index)); nums.remove(index); k = k % fac; if (i < n) fac /= n - i; } return sb.toString(); }
- next permutation
public void nextPermutation(int[] nums) { if(nums == null || nums.length<2) return;="" int="" p="0;" for(int="" i="nums.length-2;">=0; i--){ if(nums[i]