PracticeNeetCode ↗LeetCode ↗
Given an array of distinct positive integers candidates and a target integer target, return all unique combinations where the chosen numbers sum to target. The same number may be reused any number of times.
index + 1.candidates first lets you break out of the loop early once a candidate exceeds the remaining target — cheap pruning.i + 1 for the next candidate is what represents "done considering this number, move on" in the search.candidates to enable early pruning.backtrack(start, remaining): if remaining == 0, record a copy of path.i from start to len(candidates): break if candidates[i] > remaining (sorted, so nothing later can fit either).candidates[i], recurse with backtrack(i, remaining - candidates[i]) — same i, since reuse is allowed — then pop.backtrack(0, target) and return the result.Time: O(2^target) worst case — Space: O(target) recursion depth
def combinationSum(candidates: list[int], target: int) -> list[list[int]]:
candidates.sort()
result = []
path = []
def backtrack(start: int, remaining: int) -> None:
if remaining == 0:
result.append(path[:])
return
for i in range(start, len(candidates)):
if candidates[i] > remaining:
break
path.append(candidates[i])
backtrack(i, remaining - candidates[i])
path.pop()
backtrack(0, target)
return resultHow the solution above works, piece by piece.
break as soon as one is too big: all later ones are bigger.remaining == 0: the path adds up exactly, so save a copy.start: combinations are built in non-decreasing order, which prevents the same set appearing twice in different orders.backtrack(i, remaining - candidates[i]) passes i, not i + 1, because the same number may be used again (2 + 2 + 3).path.pop() undoes the choice before trying the next candidate.The recursion tree for candidates = [2, 3, 6, 7], target = 7:
break stops the loop there. Passing i (not i + 1) lets a number be reused.