Combination/Permutation/Subset
Part I: Combination
k numbers from 1 to n
public List<List<Integer>> combine(int n, int k) { List<List<Integer>> res = new ArrayList<List<Integer>>(); 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<List<Integer>> 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<List<Integer>> combinationSum(int[] candidates, int target) { List<List<Integer>> res = new ArrayList<List<Integer>>(); 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<List<Integer>> 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<List<Integer>> combinationSum2(int[] candidates, int target) { List<List<Integer>> res = new ArrayList<List<Integer>>(); 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<List<Integer>> 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<List<Integer>> getFactors(int n) { List<List<Integer>> ret = new ArrayList<List<Integer>> (); helper(ret, new ArrayList<Integer> (), n, 2); return ret; } private void helper(List<List<Integer>> 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<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
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<List<Integer>> subsets(int[] S) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
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<List<Integer>> 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<List<Integer>> subsets(int[] nums) {
int n = nums.length;
List<List<Integer>> 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<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
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<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
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<List<Integer>> tmp = new ArrayList<List<Integer>>();
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<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
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<List<Integer>> bak = new ArrayList<List<Integer>>();
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<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
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<List<Integer>> 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; i>=0; i--){
if(nums[i]<nums[i+1]){
p=i;
break;
}
}
int q = 0;
for(int i=nums.length-1; i>p; i--){
if(nums[i]> nums[p]){
q=i;
break;
}
}
if(p==0 && q==0){
reverse(nums, 0, nums.length-1);
return;
}
int temp=nums[p];
nums[p]=nums[q];
nums[q]=temp;
if(p<nums.length-1){
reverse(nums, p+1, nums.length-1);
}
}
public void reverse(int[] nums, int left, int right){
while(left<right){
int temp = nums[left];
nums[left]=nums[right];
nums[right]=temp;
left++;
right--;
}
}