Combination Sum
Backtracking to all unique combinations that sum to target — reuse allowed, sort + prune, and Combination Sum II contrast.
- dsa
- backtracking
- interview
- Meta
The problem
Distinct positive integers candidates. Find all unique combinations that sum to target. You may reuse the same number unlimited times. Order of numbers in a combo doesn’t create duplicates ([2,2,3] once, not permutations).
candidates = [2, 3, 6, 7], target = 7
→ [[2,2,3], [7]]
Brute force
Generate all multisets / all sequences and filter — wasteful. Backtracking with an index avoids permutations of the same multiset.
Optimal: backtracking with start index
function combinationSum(
candidates: number[],
target: number
): number[][] {
candidates.sort((a, b) => a - b); // enables prune
const res: number[][] = [];
const path: number[] = [];
function dfs(start: number, remain: number) {
if (remain === 0) {
res.push([...path]);
return;
}
for (let i = start; i < candidates.length; i++) {
const c = candidates[i];
if (c > remain) break; // prune
path.push(c);
// reuse allowed → pass i, not i+1
dfs(i, remain - c);
path.pop();
}
}
dfs(0, target);
return res;
}
| Time | exponential in target/min(coin); prune helps |
| Space | O(target/min) depth + output |
Why start and reuse i?
- Always pick candidates at index ≥
start→ combinations stay non-decreasing → no permutation dupes. - Passing
i(noti+1) allows reusingcandidates[i].
Walk target=7, [2,3,6,7]
2 → 2 → 2 → 2 > remain stop
2 → 2 → 3 = 7 ✓
2 → 3 → 2 would be same as 2,2,3 but start index prevents reordering
3 → ...
6 → 6 < 7, next ≥ 6 too big
7 → 7 ✓
Contrast: Combination Sum II
Candidates may have duplicates, each used at most once. Sort, pass i+1, skip equal neighbors at same depth:
// sketch difference only
// if (i > start && candidates[i] === candidates[i-1]) continue;
// dfs(i + 1, remain - c);
Edge cases
- Empty candidates
- Target smaller than min candidate →
[] - Single candidate equals target
- Large target — discuss pruning and output size
Common mistakes
- Using permutations (swap-based) and deduping with a Set of joined strings
- Passing
i+1when reuse is required - Forgetting to copy
pathwhen pushing tores
Interview delivery
- Unlimited reuse, unique combos.
- Sort + backtrack + start index.
- Prune when
c > remain. - Mention Sum II difference.
- Complexity is output-sensitive exponential.
Mental model
You’re exploring a decision tree: for each position in candidates (from start onward), either skip or take (and stay allowed to take again). Sorting + non-decreasing order means each multiset appears once.
Difference matrix interviewers care about:
| Problem | Reuse | Duplicates in input | Skip equals? |
|---|---|---|---|
| Combination Sum | yes | no | n/a |
| Combination Sum II | no | yes | yes at same depth |
| Combination Sum III | no | fixed 1..9 | k numbers |
Pruning that matters
After sort, if (c > remain) break kills an entire suffix. Without sort you can only continue. Always sort in this problem unless constraints forbid.
Out-loud answer
“Unlimited reuse, unique combinations. Sort, backtrack with start index, pass i to allow reuse, prune when candidate exceeds remain. Push a copy of path when remain hits 0. Exponential output size; pruning helps constants.”
Related
- Coin Change — min count, not list all
- Subsets
- Permutations
- Letter Combinations Phone Number
- JavaScript Interview Guide