Problem Statement
Given collection of candidate
numbers (candidates) and a integer target
. Find all unique combinations in candidates where the sum is equal to the target
.There can only be one usage of each number in the candidates combination and return the answer in sorted order.
e.g., : The combination [1, 1, 2]
and [1, 2, 1]
are not unique.
Examples
Example 1:
Input: candidates = [2, 1, 2, 7, 6, 1, 5], target = 8
Output:
[
[1, 1, 6],
[1, 2, 5],
[1, 7],
[2, 6]
]
Explanation:
The combinations whose sum is equal to the target are:
1 + 1 + 6 = 8
1 + 2 + 5 = 8
1 + 7 = 8
2 + 6 = 8
Example 2:
Input: candidates = [2, 5, 2, 1, 2], target = 5
Output:
[
[1, 2, 2],
[5]
]
Explanation:
The combinations whose sum is equal to the target are:
1 + 2 + 2 = 5
5 = 5
Example 3:
Input: candidates = [2, 1, 2], target = 5
Output:
[
[1, 2, 2]
]
Explanation: The combination whose sum is equal to the target are:
1 + 2 + 2 = 5
Different Approaches
1️⃣ Recursion
Dry Run:
Let's dry run the following input:
candidates = [10, 1, 2, 7, 6, 1, 5], target = 8
After sorting, the candidates
array becomes: [1, 1, 2, 5, 6, 7, 10]
.
Iteration 1:
- Start with the first element:
1
- Add
1
, remaining target =8 - 1 = 7
- Try the next element
1
again (because duplicates are allowed at the same position in the sorted array)- Add
1
, remaining target =7 - 1 = 6
- Try next element
2
- Add
2
, remaining target =6 - 2 = 4
- Try next element
5
- Add
5
, remaining target =4 - 5 = -1
(invalid, backtrack)
- Add
- Backtrack and try
6
- Add
6
, remaining target =4 - 6 = 0
(valid combination:[1, 1, 6]
) - Add this to the result and backtrack.
- Add
- Add
- Add
- Add
Iteration 2:
- Start with the second element
1
:- Skip this as it's a duplicate of the previous
1
(index 0).
- Skip this as it's a duplicate of the previous
Iteration 3:
- Start with the third element:
2
- Add
2
, remaining target =8 - 2 = 6
- Try next element
5
- Add
5
, remaining target =6 - 5 = 1
- Try next element
6
- Add
6
, remaining target =1 - 6 = -1
(invalid, backtrack)
- Add
- Backtrack and try
7
- Add
7
, remaining target =6 - 7 = 0
(valid combination:[1, 2, 5]
).
- Add
- Add
- Add
And so on, until all possible combinations are explored.
Output:
[[1, 1, 6], [1, 2, 5], [1, 7], [2, 6]]
Code With For Loop:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
void backtrack(vector<int>& candidates, int target, vector<int>& currentCombination, vector<vector<int>>& result, int start) {
// Base case: if the target becomes zero, we have found a valid combination
if (target == 0) {
result.push_back(currentCombination);
return;
}
// Iterate over the candidates starting from the 'start' index
for (int i = start; i < candidates.size(); i++) {
// Skip duplicates (i.e., when the same element appears consecutively in the sorted list)
if (i > start && candidates[i] == candidates[i - 1]) {
continue;
}
// If the current element exceeds the target, stop further exploration (since the array is sorted)
if (candidates[i] > target) {
break;
}
// Include the current candidate
currentCombination.push_back(candidates[i]);
// Recur with the remaining target and move to the next element (i + 1 ensures no reuse)
backtrack(candidates, target - candidates[i], currentCombination, result, i + 1);
// Backtrack: remove the last added element and try other candidates
currentCombination.pop_back();
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<vector<int>> result;
vector<int> currentCombination;
// Sort the candidates to handle duplicates and make the backtracking easier
sort(candidates.begin(), candidates.end());
// Start the backtracking process
backtrack(candidates, target, currentCombination, result, 0);
return result;
}
};
int main() {
Solution solution;
vector<int> candidates = {10, 1, 2, 7, 6, 1, 5};
int target = 8;
vector<vector<int>> result = solution.combinationSum2(candidates, target);
// Output the result
cout << "Unique combinations that sum to " << target << ":\n";
for (const auto& combination : result) {
cout << "[ ";
for (int num : combination) {
cout << num << " ";
}
cout << "]\n";
}
return 0;
}
Code Without For Loop:
class Solution {
public:
void solve(vector<vector<int>>& result, vector<int>& candidates, vector<int>& output, int index, int target) {
// Base Case: Target is met
if (target == 0) {
result.push_back(output);
return;
}
// Base Case: Exceeded target or reached end of candidates
if (target < 0 || index >= candidates.size()) {
return;
}
// Option 1: Include the current candidate
output.push_back(candidates[index]);
solve(result, candidates, output, index + 1, target - candidates[index]);
output.pop_back(); // Backtrack
// Option 2: Exclude the current candidate and move to the next unique candidate
int nextIndex = index + 1;
while (nextIndex < candidates.size() && candidates[nextIndex] == candidates[index]) {
nextIndex++;
}
solve(result, candidates, output, nextIndex, target);
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
// Sort candidates to handle duplicates
sort(candidates.begin(), candidates.end());
vector<vector<int>> result;
vector<int> output;
solve(result, candidates, output, 0, target);
return result;
}
};