public class Solution {
private static int rounds;
public static void backTrack(int k, int n, int start, int[] nums, List<Integer> tmp, List<List<Integer>> res) {
if (k == 0) return;
else {
for (int i=start; i<=nums.length-k; i++) {
tmp.add(nums[i]);
backTrack(k-1, n-nums[i], i+1, nums, tmp, res);
// when target is 0 and tmp.size() equals to k means we have reached the node and the sum equals to target,
// add the solution the result set
if (tmp.size() == rounds && n-nums[i] == 0) res.add(new ArrayList<>(tmp));
// before return to the parent level, remove the node we just added
tmp.remove(tmp.size()-1);
}
}
}
public List<List<Integer>> combinationSum3(int k, int n) {
rounds = k;
int[] nums = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9};
List<List<Integer>> res = new ArrayList<>();
backTrack(k, n, 0, nums, new ArrayList<>(), res);
return res;
}
}
Combination Sum I
/**
* The algorithm's flow chart would be,
* Step i. add candi[i] to the tmp list,
* Step ii. take care of the scenario which reslut set may have candi[i] by,
* if target drops to zero (reach to node), add all elements in tmp list to the result set
* then return and remove the last element in tmp list return to the parent.
* Step iii. in the for loop, i++, now consider the scenario which reslut set doesn't have candi[i-1]
*/
public class Solution {
public static void backTrack(int start, int target, int[] candi, List<Integer> tmp, List<List<Integer>> res) {
if (target < 0) return;
else if (target == 0) {
res.add(new ArrayList<>(tmp));
return;
}
else {
// using a for loop tow control if the result set has candi[i] or not
// every time i increament by 1 which excludes candi[i-1] from the result set
for (int i=start; i<candi.length; i++) {
tmp.add(candi[i]);
backTrack(i, target-candi[i], candi, tmp, res);
tmp.remove(tmp.size()-1);
}
}
}
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
backTrack(0, target, candidates, new ArrayList<>(), res);
return res;
}
}
Combination Sum II
public class Solution {
public static void backTrack(int start, int target, int[] candi, List<Integer> tmp, List<List<Integer>> res) {
if (target < 0) return;
else if (target == 0) {
res.add(new ArrayList<>(tmp));
return;
}
else {
for (int i=start; i<candi.length; i++) {
// we've sorted the array, now just check if two nearby elements are equal to avoid duplicates
// note that i != start should always be placed in front of the rest statement
// (*)
if (i != start && candi[i] == candi[i-1]) continue;
tmp.add(candi[i]);
// (*)
// difference here we cannot apply candi[i] multiple times,
// update start to i+1 after we added candi[i] to the result set
backTrack(i+1, target-candi[i], candi, tmp, res);
tmp.remove(tmp.size()-1);
}
}
}
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
// because the array may contain duplicates, sort the array first
Arrays.sort(candidates);
List<List<Integer>> res = new ArrayList<>();
backTrack(0, target, candidates, new ArrayList<>(), res);
return res;
}
}