You are given an array of n-element. You have to make subsets from the array such that no subset contain duplicates. Find out minimum number of subset possible.
Examples :
Input : arr[] = {1, 2, 3, 4}
Output :1
Explanation : A single subset can contains all values and all values are distinct.
Input : arr[] = {1, 2, 3, 3}
Output : 2
Explanation : We need to create two subsets {1, 2, 3} and {3} [or {1, 3} and {2, 3}] such that both subsets have distinct elements.
Table of Content
[Naive Solution] - Nested Loops - O(n^2) Time and O(1) Space
Let us take a look at few observations.
- If all elements are distinct, we need to make only one subset.
- If all elements are same, we need make n subsets.
- If only one element appears twice, and all other are distinct, we need to make two subsets. For example for {1, 2, 3, 2, 4}, the two subsets are {1} and {1, 2, 3, 4}
Did you see any pattern?
We basically need to find the most frequent element in the array. The result is equal to the frequency of the most frequent element. Since we have to create a subset such that each element in a subset is unique that means that all the repeating elements should be kept in a different set. Hence the maximum number of subsets that we require is the frequency of the maximum time occurring element.
Ex -> { 1 , 2 , 1 , 2 , 3 , 3 , 2 , 2 }
here
Frequency of 1 -> 2
Frequency of 2 -> 4
Frequency of 3 -> 2
Since the frequency of 2 is maximum hence we need to have at least 4 subset to keep all the 2 in different subsets and rest of element can be occupied accordingly.
The naive approach involves using two nested loops: the outer loop picks each element, and the inner loop counts the frequency of the picked element. This method is straightforward but inefficient.
#include <iostream>
using namespace std;
int minSubsets(vector<int> &arr)
{
int n = arr.size(), maxCount = 0;
int res;
for (int i = 0; i < n; i++) {
int count = 0;
for (int j = 0; j < n; j++) {
if (arr[i] == arr[j])
count++;
}
if (count > maxCount) {
maxCount = count;
res = arr[i];
}
}
return maxCount;
}
int main()
{
vector<int> arr = { 40, 50, 30, 40, 50, 30, 30 };
cout << minSubsets(arr);
return 0;
}
class GfG {
static int minSubsets(int[] arr) {
int n = arr.length, maxCount = 0, res = arr[0];
for (int i = 0; i < n; i++) {
int count = 0;
for (int j = 0; j < n; j++) {
if (arr[i] == arr[j]) count++;
}
if (count > maxCount) {
maxCount = count;
res = arr[i];
}
}
return maxCount;
}
public static void main(String[] args) {
int[] arr = {40, 50, 30, 40, 50, 30, 30};
System.out.println(minSubsets(arr));
}
}
def minSubsets(arr):
n, maxCount, res = len(arr), 0, arr[0]
for i in range(n):
count = sum(1 for j in range(n) if arr[i] == arr[j])
if count > maxCount:
maxCount = count
res = arr[i]
return maxCount
arr = [40, 50, 30, 40, 50, 30, 30]
print(minSubsets(arr))
using System;
using System.Collections.Generic;
class GFG
{
static int minSubsets(List<int> arr)
{
int n = arr.Count, maxCount = 0;
int res = 0;
for (int i = 0; i < n; i++){
int count = 0;
for (int j = 0; j < n; j++){
if (arr[i] == arr[j])
count++;
}
if (count > maxCount){
maxCount = count;
res = arr[i];
}
}
return maxCount;
}
static void Main()
{
List<int> arr = new List<int> { 40, 50, 30, 40, 50, 30, 30 };
Console.WriteLine(minSubsets(arr));
}
}
function minSubsets(arr) {
let n = arr.length, maxCount = 0, res = arr[0];
for (let i = 0; i < n; i++) {
let count = 0;
for (let j = 0; j < n; j++) {
if (arr[i] === arr[j]) count++;
}
if (count > maxCount) {
maxCount = count;
res = arr[i];
}
}
return maxCount;
}
// Driver Code
let arr = [40, 50, 30, 40, 50, 30, 30];
console.log(minSubsets(arr));
Output
3
[Better Approach] - Using Sorting - O(n log n) Time and O(1) Space
This method sorts the array first and then finds the maximum frequency by linearly traversing the sorted array. Sorting brings similar elements next to each other, making frequency counting easier.
#include <iostream>
using namespace std;
int minSubsets(vector<int>& arr)
{
// Sort the array
sort(arr.begin(), arr.end());
// Find the max frequency using linear traversal
int maxCount = 1, res = arr[0], currCount = 1;
for (int i = 1; i < arr.size(); i++) {
if (arr[i] == arr[i - 1])
currCount++;
else
currCount = 1;
if (currCount > maxCount) {
maxCount = currCount;
res = arr[i - 1];
}
}
return maxCount;
}
int main()
{
vector<int> arr = {40, 50, 30, 40, 50, 30, 30};
cout << minSubsets(arr);
return 0;
}
import java.util.*;
class GFG {
static int minSubsets(int[] arr)
{
// Sort the array
Arrays.sort(arr);
// Find the max frequency using linear traversal
int maxCount = 1, res = arr[0], currCount = 1;
for (int i = 1; i < arr.length; i++) {
if (arr[i] == arr[i - 1])
currCount++;
else
currCount = 1;
if (currCount > maxCount) {
maxCount = currCount;
res = arr[i - 1];
}
}
return maxCount;
}
public static void main(String[] args)
{
int[] arr = {40, 50, 30, 40, 50, 30, 30};
System.out.println(minSubsets(arr));
}
}
def minSubsets(arr):
# Sort the array
arr.sort()
# Find the max frequency using linear traversal
maxCount, res, currCount = 1, arr[0], 1
for i in range(1, len(arr)):
if arr[i] == arr[i - 1]:
currCount += 1
else:
currCount = 1
if currCount > maxCount:
maxCount = currCount
res = arr[i - 1]
return maxCount
arr = [40, 50, 30, 40, 50, 30, 30]
print(minSubsets(arr))
using System;
class GFG {
static int minSubsets(int[] arr)
{
// Sort the array
Array.Sort(arr);
// Find the max frequency using linear traversal
int maxCount = 1, res = arr[0], currCount = 1;
for (int i = 1; i < arr.Length; i++) {
if (arr[i] == arr[i - 1])
currCount++;
else
currCount = 1;
if (currCount > maxCount) {
maxCount = currCount;
res = arr[i - 1];
}
}
return maxCount;
}
static void Main()
{
int[] arr = {40, 50, 30, 40, 50, 30, 30};
Console.WriteLine(minSubsets(arr));
}
}
function minSubsets(arr)
{
// Sort the array
arr.sort((a, b) => a - b);
// Find the max frequency using linear traversal
let maxCount = 1, res = arr[0], currCount = 1;
for (let i = 1; i < arr.length; i++) {
if (arr[i] === arr[i - 1])
currCount++;
else
currCount = 1;
if (currCount > maxCount) {
maxCount = currCount;
res = arr[i - 1];
}
}
return maxCount;
}
// Driver Code
let arr = [40, 50, 30, 40, 50, 30, 30];
console.log(minSubsets(arr));
Output
3
[Expected Approach] - Using Hashing - O(n) Time and O(n) Space
Using a hash table, this approach stores each element's frequency and then finds the element with the maximum frequency.
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
int minSubsets(vector<int>& arr)
{
// Insert all elements in hash.
unordered_map<int, int> freq;
for (int i = 0; i < arr.size(); i++)
freq[arr[i]]++;
// find the max frequency
int maxCount = 0, res = -1;
for (auto i : freq) {
if (maxCount < i.second) {
res = i.first;
maxCount = i.second;
}
}
return maxCount;
}
int main()
{
vector<int> arr = {40,50,30,40,50,30,30};
cout << minSubsets(arr);
return 0;
}
import java.util.*;
class GFG {
static int minSubsets(int[] arr)
{
// Insert all elements in hash.
HashMap<Integer, Integer> freq = new HashMap<>();
for (int i = 0; i < arr.length; i++)
freq.put(arr[i], freq.getOrDefault(arr[i], 0) + 1);
// find the max frequency
int maxCount = 0, res = -1;
for (Map.Entry<Integer, Integer> i : freq.entrySet()) {
if (maxCount < i.getValue()) {
res = i.getKey();
maxCount = i.getValue();
}
}
return maxCount;
}
public static void main(String[] args)
{
int[] arr = {40,50,30,40,50,30,30};
System.out.println(minSubsets(arr));
}
}
def minSubsets(arr):
# Insert all elements in hash.
freq = {}
for i in range(len(arr)):
freq[arr[i]] = freq.get(arr[i], 0) + 1
# find the max frequency
maxCount, res = 0, -1
for key, value in freq.items():
if maxCount < value:
res = key
maxCount = value
return maxCount
arr = [40,50,30,40,50,30,30]
n = len(arr)
print(minSubsets(arr))
using System;
using System.Collections.Generic;
class GFG {
static int minSubsets(int[] arr)
{
// Insert all elements in hash.
Dictionary<int, int> freq = new Dictionary<int, int>();
for (int i = 0; i < arr.Length; i++)
freq[arr[i]] = freq.ContainsKey(arr[i])? freq[arr[i]] + 1 : 1;
// find the max frequency
int maxCount = 0, res = -1;
foreach (var i in freq) {
if (maxCount < i.Value) {
res = i.Key;
maxCount = i.Value;
}
}
return maxCount;
}
public static void Main(string[] args)
{
int[] arr = {40,50,30,40,50,30,30};
Console.WriteLine(minSubsets(arr));
}
}
function minSubsets(arr) {
// Insert all elements in hash.
let freq = {};
for (let i = 0; i < arr.length; i++) {
freq[arr[i]] = (freq[arr[i]] || 0) + 1;
}
// find the max frequency
let maxCount = 0, res = -1;
for (let key in freq) {
if (maxCount < freq[key]) {
res = key;
maxCount = freq[key];
}
}
return maxCount;
}
let arr = [40,50,30,40,50,30,30];
let n = arr.length;
console.log(minSubsets(arr));
Output
3