Problem
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.
It is guaranteed that the number of unique combinations that sum up to target
is less than 150
combinations for the given input.
Examples
Example 1:
|
|
Example 2:
|
|
Example 3:
|
|
Constraints
1 <= candidates.length <= 30
2 <= candidates[i] <= 40
- All elements of
candidates
are distinct. 1 <= target <= 40
Note
|
|
Warning : DO NOT USE LIBRARY FUNCTION FOR GENERATING COMBINATIONS. Example : itertools.combinations in python.
Solution
Method 1 - Backtracking
The first impression of this problem should be depth-first search(DFS). To solve DFS problem, recursion is a normal implementation.
Note that the candidates array is not sorted, we need to sort it first, if we need sorted output from the list. But this is not necessary.
Backtracking the wrong way
Also, normal recursion decision tree may have issues. For e.g. for array [2,3,6,7]
, when we choose 2, it may have 3 later. So, when we come to number 3
, we should make sure, that we don’t take 2
again, as that will result in duplicates.
graph TD Root["[]"] Root --> A("[2]") Root --> B("[3]") Root --> C("[6]") Root --> D("[7]") A --> AA("[2, 2]") A --> AB("[2, 3]") A --> AC("[2, 6]") A --> AD("[2, 7]") B --> BA("[3, 2]") B --> BB("[3, 3]") B --> BC("[3, 6]") B --> BD("[3, 7]") C --> CA("[6, 2]") C --> CB("[6, 3]") C --> CC("[6, 6]") C --> CD("[6, 7]") D --> DA("[7, 2]") D --> DB("[7, 3]") D --> DC("[7, 6]") D --> DD("[7, 7]") AA --> AAA("[2, 2, 2]") & AAB("[2, 2, 3]"):::Red & N1("...") AB --> ABA("[2, 3, 2]"):::Red & N2("...") classDef Red fill:#FF4C4C,stroke:#d9d9d9,font-size:14px,text-align:center;
Backtracking the correct way
So, we have to take 1 index and keep on adding it, till we find the solution.
Video explanation
Here is the video explaining this method in detail. Please check it out:
Code
|
|
|
|
|
|
Complexity
- ⏰ Time complexity:
O(n^d)
wheren
is length of candidates, andd
is depth of the tree, which is equal to d =target / min(candidates)
.- At each level of the recursion, we explore all possible elements starting from the current candidate’s position (due to the ordering constraint). 1. The depth of the recursive tree is determined by how many times we can add the smallest number in
candidates
before exceeding the target. This is roughlytarget / min(candidates)
. Let’s call this depthd
. -
- At each node, the number of choices (branches) is at most the size of
candidates
(n
). So, in the worst case, the number of nodes explored is proportional to the branching factor raised to the depth:n^d
.
- At each node, the number of choices (branches) is at most the size of
- At each level of the recursion, we explore all possible elements starting from the current candidate’s position (due to the ordering constraint). 1. The depth of the recursive tree is determined by how many times we can add the smallest number in
- 🧺 Space complexity:
O(d)
. The recursion depth is at mostd = target / min(candidates)
. Each recursive call takes up space on the call stack.