Saturday, 7 Mar 2026

Solve Combination Sum with Recursion & Backtracking | DSA Guide

Understanding Combination Sum

Solving Combination Sum (Leetcode Problem 39) requires generating all unique combinations where candidate numbers sum to a target. This problem teaches core recursion and backtracking patterns essential for technical interviews. After analyzing this video, I believe the key insight is handling infinite inclusions through strategic index management.

Problem Statement and Example

Given candidates [2,3,5] and target 8, valid combinations are:

  • [2,2,2,2] (sum=8)
  • [2,3,3] (sum=8)
  • [3,5] (sum=8)

Critical constraints:

  1. Same candidate may be reused infinitely
  2. Solutions must be unique combinations

Core Recursion Strategy

Three Choices Per Element

Every element has three possibilities:

  1. Single Inclusion: Add once and move to next index
  2. Multiple Inclusion: Add and reconsider same index
  3. Exclusion: Skip element entirely
def backtrack(index, target, path):
    # Base cases first
    if target == 0: 
        results.append(path.copy())
        return
    if target < 0 or index == len(candidates):
        return
    
    # 1. Single inclusion choice
    path.append(candidates[index])
    backtrack(index + 1, target - candidates[index], path)  # Index increments
    path.pop()
    
    # 2. Multiple inclusion choice
    path.append(candidates[index])
    backtrack(index, target - candidates[index], path)  # Index remains
    path.pop()
    
    # 3. Exclusion choice
    backtrack(index + 1, target, path)  # Target unchanged

Why Backtracking is Crucial

Path manipulation enables state resetting. When exiting recursive branches (after single/multiple inclusions), we remove the last added element using path.pop(). This maintains path integrity for subsequent choices. Forgetting this causes incorrect state propagation - a common interview pitfall.

Key Implementation Details

Base Cases That Terminate Recursion

  1. Target Achieved (target == 0): Valid combination found
  2. Target Exceeded (target < 0): Further additions futile
  3. Index Out-of-Bounds: No more candidates to process

Handling Duplicate Combinations

Since candidates can be reused, we avoid duplicate results using:

results = set()
# Convert path to tuple for hashability
results.add(tuple(sorted(path.copy())))

Time Complexity: Exponential - O(2^N) in worst-case scenarios. Sorting paths before adding to set adds O(KlogK) per combination (K = path length).

Optimization Insights

Early Termination Opportunities

When candidates are sorted, we can break early if candidates[index] > remaining_target:

candidates.sort()  # Pre-sort input
if index < len(candidates) and candidates[index] > target:
    return  # Prune useless branches

Real-World Application

This pattern extends to:

  • Coin change problems
  • Subset generation
  • Permutation problems with repetitions

Actionable Checklist

  1. Sort candidates to enable pruning
  2. Initialize path and results before recursion
  3. Implement three-choice recursion with index management
  4. Remove duplicates via tuple/set conversion
  5. Test edge cases: Empty candidates/target=0

Final Solution Code

def combinationSum(candidates, target):
    def backtrack(start, target, path):
        if target == 0:
            results.add(tuple(sorted(path)))
            return
        if target < 0 or start == len(candidates):
            return
        
        # Single inclusion
        path.append(candidates[start])
        backtrack(start + 1, target - candidates[start], path)
        path.pop()
        
        # Multiple inclusion
        path.append(candidates[start])
        backtrack(start, target - candidates[start], path)
        path.pop()
        
        # Exclusion
        backtrack(start + 1, target, path)
    
    results = set()
    candidates.sort()
    backtrack(0, target, [])
    return [list(comb) for comb in results]

Recommended Practice Resources

  • Leetcode: Try "Subsets II" (Problem 90) next - builds on these concepts
  • Book: "The Algorithm Design Manual" by Skiena - excellent backtracking section
  • Visualizer: Use pythontutor.com for step-by-step recursion visualization

"Mastering backtracking transforms how you approach combinatorial problems." - Senior FAANG Interviewer

When implementing this solution, which base case do you anticipate being most challenging to debug? Share your experience in comments!

PopWave
Youtube
blog