We use backtracking to explore all combinations. Since the same number can be reused, we don't increment the index when we include a candidate. We prune branches where the remaining target becomes negative.
- Sort candidates to enable early termination.
- Start with an empty combination and the full target.
- For each candidate from the current index, subtract it from the target.
- If target becomes 0, save the combination.
- If target goes negative, break (since candidates are sorted).
- Recurse with the same index (allowing reuse).
- Time Complexity: O(N^(T/M)) where T is target, M is minimum candidate.
- Space Complexity: O(T/M) for recursion depth.
def combination_sum(candidates, target):
result = []
candidates.sort()
def backtrack(start, current, remaining):
if remaining == 0:
result.append(current[:])
return
for i in range(start, len(candidates)):
if candidates[i] > remaining:
break
current.append(candidates[i])
backtrack(i, current, remaining - candidates[i])
current.pop()
backtrack(0, [], target)
return result