Combination Sum Problem
Algorithm · Core
Step through it: Backtracking pattern
holding [ ]
Step 1 of 7
Goal: list every subset of [1, 2]. At each number we choose: take it or skip it. All the choices form a tree of decisions. Start with nothing chosen.
Step 2 of 7
Choose to take 1.
Step 3 of 7
Take 2 as well. No numbers are left, so write this subset down.
Step 4 of 7
Undo that last choice (the "back" in backtracking) and skip 2 instead. Write [1] down.
Step 5 of 7
Undo taking 1 and skip it instead: holding [ ] again.
Step 6 of 7
From [ ], take or skip 2 the same way: [2] and [ ]. The four leaves are every subset. The recipe is choose, explore, undo. If a choice breaks a rule, stop that branch early (pruning).
Step 7 of 7
Your turn.
Given a set of candidate numbers (candidates) (without duplicates) and
a target number (target), find all unique combinations in candidates where
the candidate numbers sums to target.
The same repeated number may be chosen from candidates unlimited number
of times.
Note:
- All numbers (including
target) will be positive integers. - The solution set must not contain duplicate combinations.
Examples
Input: candidates = [2,3,6,7], target = 7,
A solution set is:
[
[7],
[2,2,3]
]Input: candidates = [2,3,5], target = 8,
A solution set is:
[
[2,2,2,2],
[2,3,3],
[3,5]
]Explanations
Since the problem is to get all the possible results, not the best or the number of result, thus we don’t need to consider DP (dynamic programming), backtracking approach using recursion is needed to handle it.
Here is an example of decision tree for the situation when candidates = [2, 3] and target = 6:
0
/ \
+2 +3
/ \ \
+2 +3 +3
/ \ / \ \
+2 ✘ ✘ ✘ ✓
/ \
✓ ✘ Code
/**
* @param {number[]} candidates - candidate numbers we're picking from.
* @param {number} remainingSum - remaining sum after adding candidates to currentCombination.
* @param {number[][]} finalCombinations - resulting list of combinations.
* @param {number[]} currentCombination - currently explored candidates.
* @param {number} startFrom - index of the candidate to start further exploration from.
* @return {number[][]}
*/
function combinationSumRecursive(
candidates,
remainingSum,
finalCombinations = [],
currentCombination = [],
startFrom = 0,
) {
if (remainingSum < 0) {
// By adding another candidate we've gone below zero.
// This would mean that the last candidate was not acceptable.
return finalCombinations;
}
if (remainingSum === 0) {
// If after adding the previous candidate our remaining sum
// became zero - we need to save the current combination since it is one
// of the answers we're looking for.
finalCombinations.push(currentCombination.slice());
return finalCombinations;
}
// If we haven't reached zero yet let's continue to add all
// possible candidates that are left.
for (let candidateIndex = startFrom; candidateIndex < candidates.length; candidateIndex += 1) {
const currentCandidate = candidates[candidateIndex];
// Let's try to add another candidate.
currentCombination.push(currentCandidate);
// Explore further option with current candidate being added.
combinationSumRecursive(
candidates,
remainingSum - currentCandidate,
finalCombinations,
currentCombination,
candidateIndex,
);
// BACKTRACKING.
// Let's get back, exclude current candidate and try another ones later.
currentCombination.pop();
}
return finalCombinations;
}
/**
* Backtracking algorithm of finding all possible combination for specific sum.
*
* @param {number[]} candidates
* @param {number} target
* @return {number[][]}
*/
export default function combinationSum(candidates, target) {
return combinationSumRecursive(candidates, target);
}References
Practice
Backtracking
- Binary Tree PathsEasy
- SubsetsMedium
- Subsets IIMedium
- PermutationsMedium
- Permutations IIMedium
- CombinationsMedium
- Combination SumMedium
- Combination Sum IIMedium
- Combination Sum IIIMedium
- Letter Combinations of a Phone NumberMedium
- Generate ParenthesesMedium
- Palindrome PartitioningMedium
- Word SearchMedium
- Restore IP AddressesMedium
- Letter Case PermutationMedium
- Partition to K Equal Sum SubsetsMedium
- N-QueensHard
- Sudoku SolverHard
- Word Break IIHard
- Expression Add OperatorsHard
Spotted a mistake or something unclear? Report it on GitHub.