Combination Sum

medium backtracking combinations

Problem

Given an array of distinct integers candidates and a target integer target, return a list of all unique combinations of candidates where the chosen numbers sum to target. You may return the combinations in any order. The same number may be chosen from candidates an unlimited number of times.

Sort candidates ascending. Recurse with the current start index and remaining target. At each step, iterate i = start..n-1: stop the loop when candidates[i] > remain (sorting makes this prune correct). Otherwise pick it, recurse with i (not i + 1) so it can be reused, then pop. Hit zero — emit the path.

Inputcandidates = [2, 3, 6, 7], target = 7
Output[2,2,3] [7]
2+2+3 = 7 (repeating 2). 7 alone. 6 alone leaves 1 — no valid completion.

def combination_sum(candidates, target):
    candidates.sort()
    out, path = [], []
    def back(start, remain):
        if remain == 0:
            out.append(path.copy()); return
        for i in range(start, len(candidates)):
            if candidates[i] > remain: break
            path.append(candidates[i])
            back(i, remain - candidates[i])
            path.pop()
    back(0, target)
    return out
function combinationSum(candidates, target) {
  candidates.sort((a, b) => a - b);
  const out = [], path = [];
  function back(start, remain) {
    if (remain === 0) { out.push(path.slice()); return; }
    for (let i = start; i < candidates.length; i++) {
      if (candidates[i] > remain) break;
      path.push(candidates[i]);
      back(i, remain - candidates[i]);
      path.pop();
    }
  }
  back(0, target);
  return out;
}
List<List<Integer>> out = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
    Arrays.sort(candidates);
    back(candidates, 0, target);
    return out;
}
void back(int[] c, int start, int remain) {
    if (remain == 0) { out.add(new ArrayList<>(path)); return; }
    for (int i = start; i < c.length; i++) {
        if (c[i] > remain) break;
        path.add(c[i]);
        back(c, i, remain - c[i]);
        path.remove(path.size() - 1);
    }
}
vector<vector<int>> out;
vector<int> path;
void back(vector<int>& c, int start, int remain) {
    if (remain == 0) { out.push_back(path); return; }
    for (int i = start; i < (int)c.size(); i++) {
        if (c[i] > remain) break;
        path.push_back(c[i]);
        back(c, i, remain - c[i]);
        path.pop_back();
    }
}
vector<vector<int>> combinationSum(vector<int>& c, int target) {
    sort(c.begin(), c.end());
    back(c, 0, target);
    return out;
}
Time: O(2^T) worst case Space: O(target / min) recursion