NeetCode #490LC-40MediumBacktrackingNC 150NC 250
← Back to All Problems#490 · #40 · Combination Sum II(组合总和 II)
📌 Problem Statement & Constraints
Given a collection of candidate numbers
candidates (which may contain duplicates) and a target, return all unique combinations summing to the target, where each candidate may be used at most once. Constraints: 1 <= candidates.length <= 100, 1 <= candidates[i] <= 50, 1 <= target <= 30.💡 Core Algorithmic Approaches
- Sort the array so duplicates are adjacent, then use a loop-based backtrack that advances to
i + 1(each element used once). - Deduplicate at each recursion level by skipping a candidate equal to its predecessor in the same loop.
- The key distinction: skipping equal values within one level removes duplicate combinations, while equal values in different levels are allowed.
- Pruning with
candidates[j] > remainis valid after sorting.
💻 Benchmark Python3 Implementation
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
candidates.sort() # duplicates become adjacent
res = []
def dfs(start: int, path: List[int], remain: int) -> None:
if remain == 0:
res.append(path[:])
return
for j in range(start, len(candidates)):
# skip duplicates at THIS level (not across levels)
if j > start and candidates[j] == candidates[j - 1]:
continue
if candidates[j] > remain:
break # sorted -> no later value fits either
path.append(candidates[j])
dfs(j + 1, path, remain - candidates[j]) # each used once
path.pop()
dfs(0, [], target)
return res⚡ Complexity Deep Dive
⏱️ Time Complexity
O(2^n) worst case, bounded by the number of valid combinations.
💾 Space Complexity
O(n) for the recursion path.
⚠️ Interview Pitfalls & Follow-ups
- Using
j > 0instead ofj > startin the duplicate skip: that would wrongly skip values that are legitimately repeated across different levels. - Not sorting: duplicates would not be adjacent and the skip would not work.
- Advancing to
jinstead ofj + 1: elements could be reused, contradicting the statement. - Using
continueinstead ofbreakfor the pruning:breakis valid because the array is sorted, and it is much faster.