66. Combination Sum
candidates are distinct positive integers. Return every unique combination that sums to target. Each number may be used any number of times. Combinations are unique by their multiset; any order.
Example 1
candidates = [2,3,6,7], target = 7[[2,2,3],[7]]Example 2
candidates = [2,3,5], target = 8[[2,2,2,2],[2,3,3],[3,5]]Hint 1
Recurse with the same start index to allow reuse.
Hint 2
Only move forward in the list, so the same multiset is never produced twice.
Approach 1: Backtracking ✅
Choose candidates in non-decreasing index order; prune when the remainder goes negative.
Reference solution for Backtracking (time Exponential, space O(target)). Each solution passes every test in all four languages.
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
res, path = [], []
def backtrack(start, remain):
if remain == 0:
res.append(path[:])
return
for i in range(start, len(candidates)):
if candidates[i] <= remain:
path.append(candidates[i])
backtrack(i, remain - candidates[i]) # i, not i+1: reuse allowed
path.pop()
backtrack(0, target)
return resclass Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
backtrack(candidates, 0, target, new ArrayList<>(), res);
return res;
}
private void backtrack(int[] c, int start, int remain, List<Integer> path, List<List<Integer>> res) {
if (remain == 0) { res.add(new ArrayList<>(path)); return; }
for (int i = start; i < c.length; i++) {
if (c[i] > remain) continue;
path.add(c[i]);
backtrack(c, i, remain - c[i], path, res); // i: reuse allowed
path.remove(path.size() - 1);
}
}
}class Solution {
void backtrack(vector<int>& c, int start, int remain, vector<int>& path, vector<vector<int>>& res) {
if (remain == 0) { res.push_back(path); return; }
for (int i = start; i < (int)c.size(); i++) {
if (c[i] > remain) continue;
path.push_back(c[i]);
backtrack(c, i, remain - c[i], path, res); // i: reuse allowed
path.pop_back();
}
}
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<int>> res;
vector<int> path;
backtrack(candidates, 0, target, path, res);
return res;
}
};function combinationSum(candidates, target) {
const res = [], path = [];
const backtrack = (start, remain) => {
if (remain === 0) { res.push([...path]); return; }
for (let i = start; i < candidates.length; i++) {
if (candidates[i] > remain) continue;
path.push(candidates[i]);
backtrack(i, remain - candidates[i]); // i: reuse allowed
path.pop();
}
};
backtrack(0, target);
return res;
}Try solving it yourself first. Interviewers care more about how you explain the approach than about the finished code.
Watch the core idea of this problem step by step. Change the input and press Visualize.
Explained in the lesson Recursion & Backtracking.
Run your code to see results here.