Given an array of distinct integers candidates
and a target integer target
, return a list of all unique combinations of candidates
where the chosen numbers sum to target
. You may return the combinations in any order.
The same number may be chosen from candidates
an unlimited number of times. Two combinations are unique if the frequency of at least one of the chosen numbers is different.
The test cases are generated such that the number of unique combinations that sum up to target
is less than 150
combinations for the given input.
Example 1:
Input: candidates = [2,3,6,7], target = 7 Output: [[2,2,3],[7]] Explanation: 2 and 3 are candidates, and 2 + 2 + 3 = 7. Note that 2 can be used multiple times. 7 is a candidate, and 7 = 7. These are the only two combinations.
Example 2:
Input: candidates = [2,3,5], target = 8 Output: [[2,2,2,2],[2,3,3],[3,5]]
Example 3:
Input: candidates = [2], target = 1 Output: []
Constraints:
1 <= candidates.length <= 30
2 <= candidates[i] <= 40
candidates
are distinct.1 <= target <= 40
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach for the Combination Sum problem is like trying every single possible combination of numbers to see if any of them add up to the target. We explore all branches, even if they seem unlikely, until we find all the valid combinations. It's like rummaging through every corner of a room to find a specific item.
Here's how the algorithm would work step-by-step:
def combination_sum_brute_force(candidates, target):
results = []
def backtrack(remaining_target, combination, start_index):
# If we've found a valid combination
if remaining_target == 0:
results.append(combination[:])
return
# If we've overshot, this combination is invalid
if remaining_target < 0:
return
# Iterate through the candidates, starting at start_index
for i in range(start_index, len(candidates)):
candidate = candidates[i]
# Add the current candidate to the combination
combination.append(candidate)
# Recursively call backtrack with updated target
# Allow duplicates by staying on same index
backtrack(remaining_target - candidate, combination, i)
# Backtrack: Remove the last added candidate
# to explore other possibilities.
combination.pop()
backtrack(target, [], 0)
return results
The best way to solve this problem is by systematically exploring possibilities and making smart choices to avoid redundant work. We'll use a method that builds up combinations step-by-step, ensuring we only consider valid solutions and avoid repeating the same combinations in different orders.
Here's how the algorithm would work step-by-step:
def combination_sum(candidates, target): result_combinations = []
def find_combinations(remaining_target, current_combination, start_index):
# If target is reached, add combination
if remaining_target == 0:
result_combinations.append(current_combination[:])
return
#If target is negative, end search
if remaining_target < 0:
return
# Iterate through the candidates
for i in range(start_index, len(candidates)): #Explore combinations using current candidate current_combination.append(candidates[i])
find_combinations(remaining_target - candidates[i], current_combination, i)
#Backtrack and remove the last element
current_combination.pop()
find_combinations(target, [], 0)
return result_combinations
Case | How to Handle |
---|---|
Null or empty candidates array | Return an empty list as there are no numbers to form combinations. |
Target is zero | Return a list containing a single empty list, representing the only combination that sums to zero. |
Target is negative | Return an empty list as no combinations of positive numbers can sum to a negative target. |
Candidates array contains zero | Include zero in combinations as many times as needed to reach the target if zero is present in the candidates. |
Candidates array contains negative numbers | The problem statement specifies distinct *integers*, but if negatives were allowed, consider that a number can be added and subtracted to reach the target; be sure to handle to avoid infinite recursion. |
Large target value with small candidate values leading to deep recursion | Be aware of potential stack overflow errors with recursive solutions; consider iterative approaches if necessary. |
No combination sums to the target | The backtracking algorithm will explore all possibilities and return an empty list if no valid combination is found. |
Candidates array contains very large numbers causing potential integer overflow | Be mindful of potential integer overflow during summation and choose appropriate data types or add checks to prevent it. |