VOOZH about

URL: https://dev.to/jaspreet_singh_86ae1740ac/combination-sum-ii-backtracking-m0a

⇱ Combination Sum II | Backtracking - DEV Community


Problem Statement

Given a collection of candidate numbers candidates and a target number target, find all unique combinations where the chosen numbers sum to the target.

Each number may be used at most once.

The solution set must not contain duplicate combinations.


Brute Force Intuition

Generate all possible subsets and check:

Does subset sum == target ?

Store valid subsets in a Set to remove duplicates.

This works but generates many duplicate combinations unnecessarily.

Complexity

  • Time Complexity: O(2ᴺ × N)
  • Space Complexity: O(2ᴺ)

Moving Towards the Optimal Approach

Notice:

candidates = [1,1,2]
target = 3

Without handling duplicates:

First 1 + 2 => [1,2]

Second 1 + 2 => [1,2]

Duplicate answer generated.

Instead of removing duplicates later, we can prevent them from being created.


Pattern Recognition

Whenever you see:

  • Generate all combinations
  • Duplicates present
  • Unique answers required

Think:

Sort + Backtracking + Skip Duplicates


Key Observations

1. Sort the Array

Arrays.sort(candidates);

After sorting:

[1,1,2,5,6,7,10]

Duplicates become adjacent.


2. Skip Duplicate Choices

if(i > index && candidates[i] == candidates[i - 1])
 continue;

Meaning:

At the same recursion level, only consider the first occurrence.


3. Use Element Only Once

After picking:

helper(i + 1, ...)

not

helper(i, ...)

because reuse is not allowed.


Optimal Java Solution

import java.util.*;

class Solution {

 public List<List<Integer>> combinationSum2(int[] candidates,
 int target) {

 Arrays.sort(candidates);

 List<List<Integer>> ans = new ArrayList<>();

 helper(0,
 candidates,
 target,
 new ArrayList<>(),
 ans);

 return ans;
 }

 private void helper(int index,
 int[] candidates,
 int target,
 List<Integer> ds,
 List<List<Integer>> ans) {

 if (target == 0) {
 ans.add(new ArrayList<>(ds));
 return;
 }

 for (int i = index; i < candidates.length; i++) {

 if (i > index &&
 candidates[i] == candidates[i - 1]) {
 continue;
 }

 if (candidates[i] > target) {
 break;
 }

 ds.add(candidates[i]);

 helper(i + 1,
 candidates,
 target - candidates[i],
 ds,
 ans);

 ds.remove(ds.size() - 1);
 }
 }
}

Dry Run

Input

candidates = [10,1,2,7,6,1,5]
target = 8

After Sorting:

[1,1,2,5,6,7,10]

Valid Combinations

[1,1,6]
[1,2,5]
[1,7]
[2,6]

Why Skip Duplicates?

Suppose:

index = 0

1 1 2
↑ ↑

If we start a combination using both 1s separately at the same level:

[1,2]
[1,2]

duplicate answers appear.

Hence:

if(i > index && nums[i] == nums[i - 1])
 continue;

Complexity Analysis

Metric Complexity
Time Complexity O(2ᴺ)
Space Complexity O(N)

Recursion depth is at most N.


Interview One-Liner

Sort the array, use backtracking to generate combinations, move to the next index after picking an element, and skip duplicate elements at the same recursion level.


Pattern Learned

Combination Sum I
=
Unlimited Reuse
=
Stay at Same Index

Combination Sum II
=
Use Once
+
Duplicates Present
=
Move Forward
+
Skip Duplicates

Similar Problems

  • Subsets II
  • Combination Sum II
  • Permutations II
  • N Queens
  • Palindrome Partitioning