Given an array arr[] of integers and an integer target, find all unique combinations of elements where the sum of the chosen elements is equal to target.
Note: Each element in the array can be used at most once in the combination.
Examples:
Input: arr[] = [1, 2, 3], target = 5
Output: [[2, 3]]
Explanation: There is only one unique combinations whose sum is equal to the target.Input: arr[] = [1, 3, 2, 2, 2], target = 4
Output: [[1, 3], [2, 2]]
Explanation: There are two unique possible combinations whose sum is equal to target.
[Approach] Using Recursion and Backtracking
The idea is to sort the array and explore all possible combinations of numbers that add up to the target. For each element, we reduce the target by its value and continue the process recursively. If at any point the target becomes zero, it means we have found a valid combination. On the other hand, if the target goes negative, we backtrack and discard that path.
Pseudo-code Idea
Base cases:
- If target < 0 : not a valid combination, so return back.
- If target == 0 : valid combination, so store it as an answer.
Recursive choices:
At each step, we have two options:
- Pick the current element, reduce the target by arr[i] and call recursion with (i+1, target - arr[i]). Increment in index (i+1) because each element can only be used once.
- Skip the current element, move to the next index (i+1, target) but also skip all duplicates of the current element to avoid repeating the same combination.
Why do we sort the array?
We sort the array to avoid duplicate combinations.
Example: arr[] = [1, 2, 3, 2], target = 5
- Without sorting, possible combinations might look like: [1, 2, 2], [2, 3], [3, 2]
- After sorting (arr[] = [1, 2, 2, 3]), the combinations become: [1, 2, 2], [2, 3]
Now duplicates like [3,2] are automatically avoided.
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
// Function to find all unique combination of
// arr such that their sum is target
void findCombinations(vector<int> &arr, int index, int target,
vector<int> &curr, vector<vector<int>> &res) {
// If a unique combination is found
if (target == 0) {
res.push_back(curr);
return;
}
// Target is less than 0 or array is exhausted, return to
// explore other options
if (target < 0 || index >= arr.size())
return;
for (int i = index; i < arr.size(); i++) {
// Check if it is repeated or not
if (i > index && arr[i] == arr[i - 1])
continue;
// Take the element into the combination
curr.push_back(arr[i]);
findCombinations(arr, i + 1, target - arr[i], curr, res);
// Remove element from the combination
curr.pop_back();
}
}
// Function to find all combination
// of the given elements
vector<vector<int>> uniqueCombinations(vector<int> &arr,
int target) {
// Sort the arr to handle duplicates
sort(arr.begin(), arr.end());
vector<vector<int>> res;
vector<int> curr;
findCombinations(arr, 0, target, curr, res);
return res;
}
int main() {
vector<int> arr = {1, 3, 2, 2, 2};
int target = 4;
vector<vector<int>> res =
uniqueCombinations(arr, target);
for (int i = 0; i < res.size(); i++) {
for (int j = 0; j < res[i].size(); j++) {
cout << res[i][j] << " ";
}
cout << endl;
}
return 0;
}
import java.util.ArrayList;
import java.util.Arrays;
class GFG {
// Function to find all unique combination of
// arr such that their sum is target
static void findCombinations(int[] arr, int index, int target,
ArrayList<Integer> curr, ArrayList<ArrayList<Integer>> res) {
// If a unique combination is found
if (target == 0) {
res.add(new ArrayList<>(curr));
return;
}
// Target is less than 0 or array is exhausted,
// return to explore other options
if (target < 0 || index >= arr.length)
return;
for (int i = index; i < arr.length; i++) {
// Check if it is repeated or not
if (i > index && arr[i] == arr[i - 1])
continue;
// Take the element into the combination
curr.add(arr[i]);
// Recursive call
findCombinations(arr, i + 1, target - arr[i], curr, res);
// Remove element from the combination
curr.remove(curr.size() - 1);
}
}
// Function to find all combination
// of the given elements
static ArrayList<ArrayList<Integer>>
uniqueCombinations (int[] arr, int target) {
Arrays.sort(arr);
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
ArrayList<Integer> curr = new ArrayList<>();
findCombinations(arr, 0, target, curr, res);
return res;
}
public static void main(String[] args) {
int[] arr = { 1, 3, 2, 2, 2 };
int target = 4;
ArrayList<ArrayList<Integer>> res = uniqueCombinations(arr, target);
for (ArrayList<Integer> combination : res) {
for (int num : combination) {
System.out.print(num + " ");
}
System.out.println();
}
}
}
# Function to find all unique combination of
# arr such that their sum is target
def findCombinations(arr, index, target, curr, res):
# If a unique combination is found
if target == 0:
res.append(list(curr))
return
# Target is less than 0 or array is exhausted, return to
# explore other options
if target < 0 or index >= len(arr):
return
for i in range(index, len(arr)):
# Check if it is repeated or not
if i > index and arr[i] == arr[i - 1]:
continue
# Take the element into the combination
curr.append(arr[i])
# Recursive call
findCombinations(arr, i + 1, target - arr[i], curr, res)
# Remove element from the combination
curr.pop()
def uniqueCombinations(arr, target):
# Sort the arr to handle duplicates
arr.sort()
res = []
curr = []
findCombinations(arr, 0, target, curr, res)
return res
if __name__ == "__main__":
arr = [1, 3, 2, 2, 2]
target = 4
res = uniqueCombinations(arr, target)
for combination in res:
print(" ".join(map(str, combination)))
using System;
using System.Collections.Generic;
class GfG {
// Function to find all unique combination of
// arr such that their sum is target
static void findCombinations(List<int> arr, int index, int target,
List<int> curr, List<List<int>> res) {
// If a unique combination is found
if (target == 0) {
res.Add(new List<int>(curr));
return;
}
// Target is less than 0 or array is exhausted, return to
// explore other options
if (target < 0 || index >= arr.Count) {
return;
}
for (int i = index; i < arr.Count; i++) {
// Check if it is repeated or not
if (i > index && arr[i] == arr[i - 1])
continue;
// Take the element into the combination
curr.Add(arr[i]);
// Recursive call
findCombinations(arr, i + 1, target - arr[i], curr, res);
// Remove element from the combination
curr.RemoveAt(curr.Count - 1);
}
}
// Function to find all combination
// of the given elements
static List<List<int>> uniqueCombinations(
List<int> arr, int target) {
// Sort the arr to handle duplicates
arr.Sort();
List<List<int>> res = new List<List<int>>();
List<int> curr = new List<int>();
findCombinations(arr, 0, target, curr, res);
return res;
}
static void Main() {
List<int> arr = new List<int> { 1, 3, 2, 2, 2 };
int target = 4;
List<List<int>> res = uniqueCombinations(arr, target);
foreach (var combination in res) {
Console.WriteLine( string.Join(" ", combination));
}
}
}
// Function to find all unique combination of
// arr such that their sum is target
function findCombinations(arr, index, target, curr, res) {
// If a unique combination is found
if (target === 0) {
res.push([...curr]);
return;
}
// Target is less than 0 or array isexhausted, return to
// explore other options
if (target < 0 || index >= arr.length) {
return;
}
for (let i = index; i < arr.length; i++) {
// Check if it is repeated or not
if (i > index && arr[i] === arr[i - 1]) {
continue;
}
// Take the element into the combination
curr.push(arr[i]);
findCombinations(arr, i + 1, target - arr[i], curr, res);
// Remove element from the combination
curr.pop();
}
}
function uniqueCombinations(arr, target) {
// Sort the arr to handle duplicates
arr.sort((a, b) => a - b);
const res = [];
const curr = [];
findCombinations(arr, 0, target, curr, res);
return res;
}
// Driver Code
const arr = [1, 3, 2, 2, 2];
const target = 4;
const res = uniqueCombinations(arr, target);
res.forEach(combination => console.log(` ${combination.join(" ")} `));
Output
1 3 2 2
Time Complexity: O(n*2n), where 2n comes from generating all subsets and n from copying/traversing elements in each subset.
Auxiliary Space: O(n)