Given an array arr[] of positive integers, Find all the unique subsets of the array.
A subset is any selection of elements from an array, where the order does not matter, and no element appears more than once. It can include any number of elements, from none (the empty subset) to all the elements of the array.
Note: If the array contains duplicate elements, the same subset should not appear more than once in the output. Only unique subsets should be included.
Examples:
Input: arr[] = [1, 5, 6]
Output: [[],[1], [1, 5], [1, 6], [5], [5, 6], [6], [1, 5, 6]]
Explanation: The Unique subset are [],[1], [1, 5], [1, 6], [5], [5, 6], [6], and [1, 5, 6]
Input: arr[] = [1, 2, 2]
Output: [[],[1], [1, 2], [1, 2, 2], [2], [2, 2]]
Explanation: The Unique subset are [],[1], [1, 2], [1, 2, 2], [2], [2, 2]
[Approach - 1] Using Backtracking
The idea is to use backtracking to explore all possible subsets of the array. We first sort the array so that duplicate elements appear together. This allows us to easily skip over duplicates at the same recursion level and avoid generating the same subset more than once.
At each step, we add the current subset to the result, then try including each remaining element one by one. For every element, we choose it, recurse to explore further subsets, and then remove it (backtrack) to explore other possibilities. By repeating this process, we generate all unique subsets of the array.
C++
#include <iostream>
#include<vector>
#include <algorithm>
using namespace std;
// Helper function to find all unique subsets
void findSubsetsRec(vector<int> &arr, int idx, vector<int> &subset,
vector<vector<int>> &res){
// include current subset
res.push_back(subset);
for (int i = idx; i < arr.size(); i++) {
// Skip duplicates at the same recursion level
if (i > idx && arr[i] == arr[i - 1]) continue;
subset.push_back(arr[i]);
findSubsetsRec(arr, i + 1, subset, res);
// backtrack
subset.pop_back();
}
}
vector<vector<int>> findSubsets(vector<int> &arr){
// sort to handle duplicates
sort(arr.begin(), arr.end());
vector<vector<int>> res;
vector<int> subset;
findSubsetsRec(arr, 0, subset, res);
return res;
}
int main() {
vector<int> arr = {1, 2, 2};
vector<vector<int>> result = findSubsets(arr);
for (int i = 0; i < result.size(); i++) {
cout << "[";
for (int j = 0; j < result[i].size(); j++) {
cout << result[i][j];
if (j != result[i].size() - 1) cout << ", ";
}
cout << "]" << endl;
}
return 0;
}
Java
import java.util.Arrays;
import java.util.ArrayList;
class GFG {
// Helper function to find all unique subsets
static void findSubsetsRec(int[] arr, int idx,
ArrayList<Integer> subset, ArrayList<ArrayList<Integer>> res) {
// include current subset
res.add(new ArrayList<>(subset));
for (int i = idx; i < arr.length; i++) {
// Skip duplicates at the same recursion level
if (i > idx && arr[i] == arr[i - 1]) continue;
subset.add(arr[i]);
findSubsetsRec(arr, i + 1, subset, res);
subset.remove(subset.size() - 1);
}
}
static ArrayList<ArrayList<Integer>> findSubsets(int[] arr) {
// sort to handle duplicates
Arrays.sort(arr);
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
findSubsetsRec(arr, 0, new ArrayList<>(), res);
return res;
}
public static void main(String[] args) {
int[] arr = {1, 2, 2};
ArrayList<ArrayList<Integer>> result = findSubsets(arr);
for (ArrayList<Integer> subset : result) {
System.out.println(subset);
}
}
}
Python
# Helper function to find all unique subsets
def findSubsetsRec(arr, idx, subset, res):
# include current subset
res.append(list(subset))
for i in range(idx, len(arr)):
# Skip duplicates at the same recursion level
if i > idx and arr[i] == arr[i - 1]:
continue
subset.append(arr[i])
findSubsetsRec(arr, i + 1, subset, res)
# backtrack
subset.pop()
def findSubsets(arr):
# sort to handle duplicates
arr.sort()
res = []
subset = []
findSubsetsRec(arr, 0, subset, res)
return res
if __name__ == "__main__":
arr = [1, 2, 2]
result = findSubsets(arr)
for i in range(len(result)):
print("[", end="")
for j in range(len(result[i])):
print(result[i][j], end="")
if j != len(result[i]) - 1:
print(", ", end="")
print("]")
C#
using System;
using System.Collections.Generic;
class GFG {
// Helper function to find all unique subsets
static void findSubsetsRec(int[] arr, int idx,
List<int> subset, List<List<int>> res) {
// include current subset
res.Add(new List<int>(subset));
for (int i = idx; i < arr.Length; i++) {
// Skip duplicates at the same recursion level
if (i > idx && arr[i] == arr[i - 1]) continue;
subset.Add(arr[i]);
findSubsetsRec(arr, i + 1, subset, res);
subset.RemoveAt(subset.Count - 1);
}
}
static List<List<int>> findSubsets(int[] arr) {
// sort to handle duplicates
Array.Sort(arr);
List<List<int>> res = new List<List<int>>();
findSubsetsRec(arr, 0, new List<int>(), res);
return res;
}
static void Main() {
int[] arr = {1, 2, 2};
List<List<int>> result = findSubsets(arr);
foreach (var subset in result) {
Console.Write("[");
for (int i = 0; i < subset.Count; i++) {
Console.Write(subset[i]);
if (i != subset.Count - 1) Console.Write(", ");
}
Console.WriteLine("]");
}
}
}
JavaScript
// Helper function to find all unique subsets
function findSubsetsRec(arr, idx, subset, res) {
// include current subset
res.push([...subset]);
for (let i = idx; i < arr.length; i++) {
// Skip duplicates at the same recursion level
if (i > idx && arr[i] === arr[i - 1]) continue;
subset.push(arr[i]);
findSubsetsRec(arr, i + 1, subset, res);
// backtrack
subset.pop();
}
}
function findSubsets(arr) {
// sort to handle duplicates
arr.sort((a, b) => a - b);
let res = [];
let subset = [];
findSubsetsRec(arr, 0, subset, res);
return res;
}
// Driver code
let arr = [1, 2, 2];
let result = findSubsets(arr);
for (let i = 0; i < result.length; i++) {
let subsetStr = "[";
for (let j = 0; j < result[i].length; j++) {
subsetStr += result[i][j];
if (j !== result[i].length - 1) subsetStr += ", ";
}
subsetStr += "]";
console.log(subsetStr);
}
Output[]
[1]
[1, 2]
[1, 2, 2]
[2]
[2, 2]
Time Complexity: O(n * (2n)), as there are 2^n subsets, and pushing each subset (of size up to n) into the result takes O(n) time
Auxiliary Space: O(n), as recursion stack space and temporary array to store result
[Another Approach - 2] Iterative Approach Using Set - O(n* 2n) Time and O(2n) Space
The idea is to build all unique subsets iteratively. We start with the empty subset {}. Then, for each element in the sorted array, we create new subsets by adding that element to every subset we have generated so far. To handle duplicates, we store all subsets in a set, which automatically removes any repeated subsets. After processing all elements, the set contains all unique subsets
C++
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
using namespace std;
vector<vector<int>> findSubsets(vector<int> &arr) {
sort(arr.begin(), arr.end());
set<vector<int>> res;
vector<int> subset;
vector<vector<int>> result;
// Insert it into the resultant set
res.insert(subset);
// Iterate over all elements
for (int i = 0; i < arr.size(); i++) {
int n = res.size();
for (auto it = res.begin(); it != res.end() && n > 0; it++) {
// Iterate through every subset
// generated till now and insert
// the current element at the end
subset = *it;
subset.push_back(arr[i]);
result.push_back(subset);
n--;
}
res.insert(result.begin(), result.end());
result.clear();
}
for (auto u : res)
result.push_back(u);
return result;
}
int main() {
vector<int> arr = {1, 2, 2};
vector<vector<int>> result = findSubsets(arr);
for (int i = 0; i < result.size(); i++)
{
cout << "[";
for (int j = 0; j < result[i].size(); j++)
{
cout << result[i][j];
if (j != result[i].size() - 1)
cout << ", ";
}
cout << "]" << endl;
}
return 0;
}
Java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Set;
import java.util.List;
import java.util.HashSet;
class GFG {
static ArrayList<ArrayList<Integer>> findSubsets(int[] arr) {
// Sort the array to handle duplicates
Arrays.sort(arr);
// Use a set to store unique subsets
Set<ArrayList<Integer>> res = new HashSet<>();
ArrayList<Integer> subset = new ArrayList<>();
ArrayList<ArrayList<Integer>> result = new ArrayList<>();
// Insert the empty subset into the set
res.add(subset);
// Iterate over all elements
for (int i = 0; i < arr.length; i++) {
int n = res.size();
// Iterate through every subset generated till now
// and insert the current element at the end
for (List<Integer> s : new ArrayList<>(res)) {
if (n-- <= 0) break;
subset = new ArrayList<>(s);
subset.add(arr[i]);
result.add(subset);
}
// Add all new subsets to the set
res.addAll(result);
result.clear();
}
result.addAll(res);
return result;
}
public static void main(String[] args) {
int[] arr = {1, 2, 2};
ArrayList<ArrayList<Integer>> result = findSubsets(arr);
for (ArrayList<Integer> subset : result) {
System.out.print("[");
for (int j = 0; j < subset.size(); j++) {
System.out.print(subset.get(j));
if (j != subset.size() - 1)
System.out.print(", ");
}
System.out.println("]");
}
}
}
Python
def findSubsets(arr):
arr.sort()
res = set()
subset = []
result = []
# Insert it into the resultant set
res.add(tuple(subset))
# Iterate over all elements
for i in range(len(arr)):
n = len(res)
tempRes = list(res)
for it in tempRes[:n]:
# Iterate through every subset
# generated till now and insert
# the current element at the end
subset = list(it)
subset.append(arr[i])
result.append(subset)
res.update(tuple(r) for r in result)
result.clear()
for u in res:
result.append(list(u))
return result
if __name__ == "__main__":
arr = [1, 2, 2]
result = findSubsets(arr)
for i in range(len(result)):
print("[", end="")
for j in range(len(result[i])):
print(result[i][j], end="")
if j != len(result[i]) - 1:
print(", ", end="")
print("]")
C#
using System;
using System.Collections.Generic;
class GFG {
static List<List<int>> findSubsets(int[] arr) {
Array.Sort(arr);
HashSet<string> seen = new HashSet<string>();
List<List<int>> result = new List<List<int>>();
// add empty subset
result.Add(new List<int>());
seen.Add("");
// iterate over all elements
for (int i = 0; i < arr.Length; i++) {
int currentSize = result.Count;
for (int j = 0; j < currentSize; j++) {
// create new subset from existing one
List<int> subset = new List<int>(result[j]);
subset.Add(arr[i]);
// convert to string key for duplicate check
string key = string.Join(",", subset);
if (!seen.Contains(key)) {
result.Add(subset);
seen.Add(key);
}
}
}
return result;
}
static void Main() {
int[] arr = { 1, 2, 2 };
List<List<int>> result = findSubsets(arr);
foreach (var subset in result) {
Console.Write("[");
for (int i = 0; i < subset.Count; i++) {
Console.Write(subset[i]);
if (i != subset.Count - 1) Console.Write(", ");
}
Console.WriteLine("]");
}
}
}
JavaScript
function findSubsets(arr) {
// sort to handle duplicates
arr.sort((a, b) => a - b);
let res = new Set();
let subset = [];
let result = [];
// Insert it into the resultant set
res.add(JSON.stringify(subset));
// Iterate over all elements
for (let i = 0; i < arr.length; i++) {
let N = res.size;
let tempRes = Array.from(res);
for (let itIndex = 0; itIndex < N; itIndex++) {
// Iterate through every subset
// generated till now and insert
// the current element at the end
let it = JSON.parse(tempRes[itIndex]);
subset = [...it];
subset.push(arr[i]);
result.push(subset);
}
// add new subsets to the set
for (let r of result) {
res.add(JSON.stringify(r));
}
result = [];
}
// convert set back to array of arrays
for (let u of res) {
result.push(JSON.parse(u));
}
return result;
}
// Driver code
let arr = [1, 2, 2];
let result = findSubsets(arr);
for (let i = 0; i < result.length; i++) {
process.stdout.write("[");
for (let j = 0; j < result[i].length; j++) {
process.stdout.write(result[i][j].toString());
if (j != result[i].length - 1) process.stdout.write(", ");
}
console.log("]");
}
Output[]
[1]
[1, 2]
[1, 2, 2]
[2]
[2, 2]
[Another Approach - 3] Iterative Approach Without Using Set - O(n* 2n) Time and O(n) Space
The idea is to make all subsets one by one while avoiding duplicates. First, sort the array so duplicate numbers are together. Start with an empty subset, and for each number, add it to the existing subsets. If the number is a duplicate, only add it to the subsets created in the previous step to prevent repeated subsets.
C++
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> findSubsets(vector<int> &arr) {
// sort to handle duplicates
sort(arr.begin(), arr.end());
vector<vector<int>> res;
vector<int> subset;
vector<vector<int>> result;
// Insert the empty subset first
res.push_back(subset);
int start, end = 0;
// Iterate over all elements
for (int i = 0; i < arr.size(); i++) {
start = 0;
// if current element is same as previous,
// only extend subsets added in previous step
if (i > 0 && arr[i] == arr[i - 1]) {
start = end + 1;
}
end = res.size() - 1;
int n = res.size();
for (int j = start; j < n; j++) {
subset = res[j];
subset.push_back(arr[i]);
res.push_back(subset);
}
}
return res;
}
int main() {
vector<int> arr = {1, 2, 2};
vector<vector<int>> result = findSubsets(arr);
for (int i = 0; i < result.size(); i++)
{
cout << "[";
for (int j = 0; j < result[i].size(); j++)
{
cout << result[i][j];
if (j != result[i].size() - 1)
cout << ", ";
}
cout << "]";
cout<<endl;
}
return 0;
}
Java
import java.util.ArrayList;
import java.util.Arrays;
class GFG {
static ArrayList<ArrayList<Integer>> findSubsets(int[] arr) {
// Sort to handle duplicates
Arrays.sort(arr);
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
ArrayList<Integer> subset;
// Insert the empty subset first
res.add(new ArrayList<>());
int start, end = 0;
// Iterate over all elements
for (int i = 0; i < arr.length; i++) {
start = 0;
// If current element is same as previous,
// only extend subsets added in previous step
if (i > 0 && arr[i] == arr[i - 1]) {
start = end + 1;
}
end = res.size() - 1;
int n = res.size();
for (int j = start; j < n; j++) {
subset = new ArrayList<>(res.get(j));
subset.add(arr[i]);
res.add(subset);
}
}
return res;
}
public static void main(String[] args) {
int[] arr = {1, 2, 2};
ArrayList<ArrayList<Integer>> result = findSubsets(arr);
for (ArrayList<Integer> subset : result) {
System.out.println(subset);
}
}
}
Python
def findSubsets(arr):
# sort to handle duplicates
arr.sort()
res = [[]]
start = 0
end = 0
for i in range(len(arr)):
start = 0
# if current element is same as previous,
# only extend subsets added in previous step
if i > 0 and arr[i] == arr[i - 1]:
start = end + 1
end = len(res) - 1
n = len(res)
for j in range(start, n):
subset = list(res[j])
subset.append(arr[i])
res.append(subset)
return res
if __name__ == "__main__":
arr = [1, 2, 2]
result = findSubsets(arr)
for i in range(len(result)):
print("[", end="")
for j in range(len(result[i])):
print(result[i][j], end="")
if j != len(result[i]) - 1:
print(", ", end="")
print("]")
C#
using System;
using System.Collections.Generic;
class GFG {
static List<List<int>> findSubsets(int[] arr) {
Array.Sort(arr);
int n = arr.Length;
List<List<int>> res = new List<List<int>>();
// start with empty subset
res.Add(new List<int>());
int start, end = 0;
for (int i = 0; i < n; i++)
{
start = 0;
// if current element is duplicate, only extend
// subsets added in previous step
if (i > 0 && arr[i] == arr[i - 1])
{
start = end + 1;
}
end = res.Count - 1;
int currentResCount = res.Count;
for (int j = start; j < currentResCount; j++)
{
// copy existing subset
List<int> subset = new List<int>(res[j]);
// add current element
subset.Add(arr[i]);
// add the new subset
res.Add(subset);
}
}
return res;
}
static void Main()
{
int[] arr = { 1, 2, 2 };
List<List<int>> result = findSubsets(arr);
foreach (var subset in result)
{
Console.Write("[");
for (int i = 0; i < subset.Count; i++)
{
Console.Write(subset[i]);
if (i != subset.Count - 1) Console.Write(", ");
}
Console.WriteLine("]");
}
}
}
JavaScript
function findSubsets(arr) {
// sort to handle duplicates
arr.sort((a, b) => a - b);
let res = [[]];
let start = 0, end = 0;
for (let i = 0; i < arr.length; i++) {
start = 0;
// if current element is same as previous,
// only extend subsets added in previous step
if (i > 0 && arr[i] === arr[i - 1]) {
start = end + 1;
}
end = res.length - 1;
let n = res.length;
for (let j = start; j < n; j++) {
let subset = res[j].slice();
subset.push(arr[i]);
res.push(subset);
}
}
return res;
}
// Driver code
let arr = [1, 2, 2];
let result = findSubsets(arr);
for (let i = 0; i < result.length; i++) {
process.stdout.write("[");
for (let j = 0; j < result[i].length; j++) {
process.stdout.write(result[i][j].toString());
if (j !== result[i].length - 1) process.stdout.write(", ");
}
console.log("]");
}
Output[]
[1]
[2]
[1, 2]
[2, 2]
[1, 2, 2]
[Approach - 4] Bit Masking - (n * 2n) Time and O(2n) Space
Prerequisite: Power Set
Represent all the numbers from 1 to 2n- 1 where n is the size of the subset in the binary format and the position for which the bits are set to be added to the array and then add that array into the result i.e to use a bit-mask pattern to generate all the combinations.
Example:
Input: arr[] = [1, 5, 6], N = 3
Explanation: Hence we will check every number from 1 to 7 i.e. till 2n-1 = 23 - 1 = 7 and empty subset.
1 => 001 => [6]
2 => 010 => [5]
3 => 011 => [5, 6]
4 => 100 => [1]
5 => 101 => [1, 6]
6 => 110 => [1, 5]
7 => 111 => [1, 5, 6]
C++
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
vector<vector<int>> findSubsets(vector<int> &arr) {
// To store the resulting subsets
set<vector<int>> res;
vector<int> subset;
int size = arr.size();
sort(arr.begin(), arr.end());
// Finding 2^N
int N = 1 << size;
for (int i = 0; i < N; i++) {
int bit = i;
subset.clear();
int pos = 0;
while (bit) {
// If the bit is set insert it into the subset
if (bit & 1) {
subset.push_back(arr[pos]);
}
pos++;
bit >>= 1;
}
res.insert(subset);
}
vector<vector<int>> result;
for (auto u : res)
result.push_back(u);
return result;
}
int main()
{
vector<int> arr = {1, 2, 2};
vector<vector<int>> result = findSubsets(arr);
for (int i = 0; i < result.size(); i++)
{
cout << "[";
for (int j = 0; j < result[i].size(); j++)
{
cout << result[i][j];
if (j != result[i].size() - 1)
cout << ", ";
}
cout << "]" << endl;
}
return 0;
}
Java
import java.util.Arrays;
import java.util.TreeSet;
import java.util.ArrayList;
class GFG {
static ArrayList<ArrayList<Integer>> findSubsets(int[] arr) {
// Sort the array to handle duplicates
Arrays.sort(arr);
// TreeSet to store unique subsets in sorted order
TreeSet<ArrayList<Integer>> res = new TreeSet<>((a, b) -> {
int n = Math.min(a.size(), b.size());
for (int i = 0; i < n; i++) {
if (!a.get(i).equals(b.get(i))) return a.get(i) - b.get(i);
}
return a.size() - b.size();
});
int size = arr.length;
int N = 1 << size; // 2^N subsets
ArrayList<Integer> subset;
// Generate all subsets using bitmasking
for (int i = 0; i < N; i++) {
int bit = i;
subset = new ArrayList<>();
int pos = 0;
while (bit > 0) {
// If the bit is set, include the element in the subset
if ((bit & 1) == 1) {
subset.add(arr[pos]);
}
pos++;
bit >>= 1;
}
res.add(subset);
}
return new ArrayList<>(res);
}
public static void main(String[] args) {
int[] arr = {1, 2, 2};
ArrayList<ArrayList<Integer>> result = findSubsets(arr);
for (ArrayList<Integer> subset : result) {
System.out.print("[");
for (int j = 0; j < subset.size(); j++) {
System.out.print(subset.get(j));
if (j != subset.size() - 1)
System.out.print(", ");
}
System.out.println("]");
}
}
}
Python
def findSubsets(arr):
# To store the resulting subsets
res = set()
subset = []
size = len(arr)
arr.sort()
# Finding 2^N
N = 1 << size
for i in range(N):
bit = i
subset.clear()
pos = 0
while bit:
# If the bit is set insert
# it into the subset
if bit & 1:
subset.append(arr[pos])
pos += 1
bit >>= 1
res.add(tuple(subset))
result = [list(u) for u in res]
return result
if __name__ == "__main__":
arr = [1, 2, 2]
result = findSubsets(arr)
for subset in result:
print("[", end="")
print(", ".join(str(x) for x in subset), end="")
print("]")
C#
using System;
using System.Collections.Generic;
class GFG {
static List<List<int>> findSubsets(int[] arr) {
// Sort to handle duplicates
Array.Sort(arr);
// To store unique subsets as strings
HashSet<string> set = new HashSet<string>();
List<List<int>> res = new List<List<int>>();
int size = arr.Length;
// 2^N subsets
int N = 1 << size;
for (int i = 0; i < N; i++) {
int bit = i;
List<int> subset = new List<int>();
int pos = 0;
while (bit > 0) {
if ((bit & 1) == 1) {
subset.Add(arr[pos]);
}
pos++;
bit >>= 1;
}
// Convert subset to string to check uniqueness
string key = string.Join(",", subset);
if (!set.Contains(key)) {
set.Add(key);
res.Add(subset);
}
}
return res;
}
static void Main()
{
int[] arr = { 1, 2, 2 };
List<List<int>> result = findSubsets(arr);
foreach (var subset in result)
{
Console.Write("[");
for (int i = 0; i < subset.Count; i++)
{
Console.Write(subset[i]);
if (i != subset.Count - 1) Console.Write(", ");
}
Console.WriteLine("]");
}
}
}
JavaScript
function findSubsets(arr) {
// To store the resulting subsets
let res = new Set();
let subset = [];
let size = arr.length;
// Sort the array
arr.sort((a, b) => a - b);
// Finding 2^N
let N = 1 << size;
for (let i = 0; i < N; i++) {
let bit = i;
subset = [];
let pos = 0;
while (bit > 0) {
// If the bit is set insert
// it into the subset
if (bit & 1) {
subset.push(arr[pos]);
}
pos++;
bit >>= 1;
}
// Convert subset to string to store in Set for
// uniqueness
res.add(subset.join(","));
}
// Convert back to array of arrays
let result = [];
for (let s of res) {
if (s.length === 0) {
result.push([]);
}
else {
result.push(s.split(",").map(Number));
}
}
return result;
}
// Driver code
let arr = [ 1, 2, 2 ];
let result = findSubsets(arr);
for (const subset of result) {
console.log("[" + subset.join(", ") + "]");
}
Output[]
[1]
[1, 2]
[1, 2, 2]
[2]
[2, 2]
Explore
DSA Fundamentals
Data Structures
Algorithms
Advanced
Interview Preparation
Practice Problem