Combination Sum
Question (LC.39)
Given an array of candidate numbers and a target, find all unique combinations from the candidate array that sum to the target.
Example
Input: candidates = [2, 3, 6, 7], target = 7
Output: [ [2, 2, 3], [7] ]A candidate can be used unlimited number of times.
Analysis
Be careful with the input, it might contain duplicates. Step 1 Remove duplicates Step 2 Define DFS(parameter/return value, recursive calls, stop condition) Step 3 Write DFS
Code
Main function
/*
How is this different from subsets?
1. dup
2. use each number unlimited number of times
3. stop at a target
*/
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> results = new ArrayList<>();
if (candidates == null || candidates.length == 0) {
return results;
}
Arrays.sort(candidates);
combDFS(results, candidates, target, 0, new ArrayList<Integer>());
return results;
}DFS Search
We can improve a bit on the stopping conditions. We don't have to go down one more level until the target becomes negative. We can simply skip the candidates in the for loop that is bigger than the current target.
Combination Sums II (LC.40)
Approach
Analysis
dup doesn't change much right?
Consider this case
We want to keep [1,1,6] but get rid of [1,2,5], [1,7]. Essentially, we want to avoid using the second 1 as the root of the search. One may attempt if (i != 0 && candidates[i] == candidates[i-1]) continue;. But it gets rid of [1,1,6] as well. We want to only avoid duplicates on the same level so i != startIndex.
Code
The smart pruning will improve performance by a lot. It will bring the runtime from 21% to 93% on LC.
Combination Sum III (LC.216)
Find all possible combinations of k numbers that add up to a target. Only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.
Example
Always run examples FIRST. Running examples can give you another chance and read and understand the question better. It can also clarify the edge cases.
Analysis
We want to find all combinations 9 choose k, such that the combSum == target.
Approach
Code
Optimization
Adding this simple if statement will boost the performance from 12 to 58 percentile.
We can also do the pruning inside the for loop (save one level/stack frame more efficient)
Combination Sum IV (LC.377)
Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target.
Example
Analysis
I originally thought this is combination with repetition. But the example shows [1,1,2], [1,2,1], and [2,1,1] are three different "combinations". In fact, under this definition, there's an infinite number of "combinations". For example, given a set [1,2,3], we can have {[1-3],[1-3],[1-3],[1-3], ...} so 3x3x3x3x3... number of combinations.
Brute Force Approach
find all combinations (where sum < target)
add it to results if combSum == target
Code
But Time Limit Exceeded ٩ʕ•͡וʔ۶
Analysis 2
Draw the recursion tree and we can observe starting from [2] has overlapping subproblems as starting from [1].
DP Approach
In addition to the overlapping subproblems, the question is only asking for returning a count instead of a collection of all combinations. Also, it is unreasonable to search for all 181997601 combinations.
Top-Down (Memoization)
Now we can handle [1,2,3], 32 case. But [3,33,333], 10000 makes the program TLE again.
Updated Version (See comments above)
Bottom-Up (Tabulation)
Simplicity is harder to achieve than complexity.
Follow Up
What if negative numbers are allowed in the given array?
Then we need to add an extra constraint on the max length of a combination. Otherwise, we can run into the an infinite long combination such as [...,-1,-1,-1,1,1,1,...].
Reference
Combination Sum IV by Grand Yang
Last updated