The "Combination Sum" problem asks us to find all unique combinations of numbers from a given list of positive integers called candidates
that add up to a specific target value. A key twist is that each number in candidates
may be used an unlimited number of times in each combination.
For instance, given candidates = [2, 3, 6, 7]
and target = 7
, a valid result would be [[2, 2, 3], [7]]
. Here, [2, 2, 3]
sums to 7 and uses the number 2 more than once.
This problem is ideally suited for a backtracking algorithm. We start at the first index of the candidates array and decide at each step whether to include the current number or skip it. If we include it, we stay at the current index to allow repeated use. If we skip it, we move to the next index.
The backtracking function takes the current index and a running sum of the selected numbers. If the running sum equals the target, we store a copy of the current combination. If it exceeds the target or we've processed all candidates, we stop exploring that path.
This recursive approach ensures all valid paths are explored, and backtracking removes the last element to try new possibilities at each level.
The use of backtracking is powerful here because we avoid unnecessary computations. For example, once our current sum exceeds the target, there's no need to go further down that path. Additionally, by only moving forward in the candidate list or staying on the current index (to allow reuse), we prevent generating duplicate combinations in different orders (like [2,3,2]
vs [2,2,3]
).
The time complexity is difficult to quantify precisely due to the branching factor and pruning, but in the worst case, it is exponential, roughly O(2^T) where T is the target value. Each recursive call explores paths that build up to the target.
The space complexity is O(T) for the recursion stack and the space used to store intermediate combinations.
The "Combination Sum" problem is a classic application of recursive backtracking with a twist — unlimited reuse of elements. It strengthens understanding of recursion, state tracking, and optimization through pruning. Practicing this problem builds a strong foundation for tackling more complex variations involving permutations, subsets, and partitioning problems.