Given an array arr[ ] of item IDs, where each element represents the ID of an item, and an integer m, remove exactly m elements from the arr[ ] such that the number of distinct item IDs remaining is minimized.
Determine and print the minimum possible number of distinct item IDs left after removing m elements.
Examples:
Input: arr[] = [2, 2, 1, 3, 3, 3], m = 3
Output: 1
Explanation: Removing {2, 2, 1} leaves {3, 3, 3}, which contains only one distinct ID..
Input: arr[] = [2, 4, 1, 5, 3, 5, 1, 3], m = 2
Output: 3
Explanation: Removing {2, 4} leaves {1, 5, 3, 5, 1, 3}, which contains three distinct IDs.
Table of Content
[Naive Approach] Using Linear Search - O(n + k ^ 2) Time O(k) Space
The idea is to first count the frequency of each element, then greedily remove elements with the smallest frequencies so that each removal eliminates a distinct element using the minimum number of deletions. We keep removing the least frequent elements until we either exhaust
mor can no longer fully remove any element, and the remaining count of elements gives the minimum number of distinct elements.
#include <bits/stdc++.h>
using namespace std;
// Function to minimize distinct elements
int distinctIds(vector<int> &arr, int m)
{
unordered_map<int, int> mp;
// Store frequency of elements
for (int x : arr)
{
mp[x]++;
}
vector<int> freq;
// Store frequencies
for (auto it : mp)
{
freq.push_back(it.second);
}
int k = freq.size();
// Repeatedly remove minimum frequency
while (m > 0)
{
int mn = INT_MAX;
int idx = -1;
// Linear search for minimum frequency
for (int i = 0; i < k; i++)
{
if (freq[i] > 0 && freq[i] < mn)
{
mn = freq[i];
idx = i;
}
}
// Remove current minimum frequency
if (idx != -1 && mn <= m)
{
m -= mn;
freq[idx] = 0;
}
else
{
break;
}
}
int res = 0;
// Count remaining distinct elements
for (int x : freq)
{
if (x > 0)
{
res++;
}
}
return res;
}
// Driver code
int main()
{
vector<int> arr = {2, 4, 1, 5, 3, 5, 1, 3};
int m = 2;
int res = distinctIds(arr, m);
cout << res;
return 0;
}
import java.util.HashMap;
import java.util.Map;
public class GfG {
// Function to minimize distinct elements
public static int distinctIds(int[] arr, int m)
{
Map<Integer, Integer> mp = new HashMap<>();
// Store frequency of elements
for (int x : arr) {
mp.put(x, mp.getOrDefault(x, 0) + 1);
}
int[] freq = new int[mp.size()];
int k = 0;
// Store frequencies
for (int val : mp.values()) {
freq[k++] = val;
}
// Repeatedly remove minimum frequency
while (m > 0) {
int mn = Integer.MAX_VALUE;
int idx = -1;
// Linear search for minimum frequency
for (int i = 0; i < k; i++) {
if (freq[i] > 0 && freq[i] < mn) {
mn = freq[i];
idx = i;
}
}
// Remove current minimum frequency
if (idx != -1 && mn <= m) {
m -= mn;
freq[idx] = 0;
}
else {
break;
}
}
int res = 0;
// Count remaining distinct elements
for (int x : freq) {
if (x > 0) {
res++;
}
}
return res;
}
public static void main(String[] args)
{
int[] arr = { 2, 4, 1, 5, 3, 5, 1, 3 };
int m = 2;
int res = distinctIds(arr, m);
System.out.println(res);
}
}
from collections import defaultdict
# Function to minimize distinct elements
def distinctIds(arr, m):
mp = defaultdict(int)
# Store frequency of elements
for x in arr:
mp[x] += 1
freq = list(mp.values())
k = len(freq)
# Repeatedly remove minimum frequency
while m > 0:
mn = float('inf')
idx = -1
# Linear search for minimum frequency
for i in range(k):
if freq[i] > 0 and freq[i] < mn:
mn = freq[i]
idx = i
# Remove current minimum frequency
if idx != -1 and mn <= m:
m -= mn
freq[idx] = 0
else:
break
res = 0
# Count remaining distinct elements
for x in freq:
if x > 0:
res += 1
return res
# Driver code
if __name__ == "__main__":
arr = [2, 4, 1, 5, 3, 5, 1, 3]
m = 2
res = distinctIds(arr, m)
print(res)
using System;
using System.Collections.Generic;
public class GfG {
// Function to minimize distinct elements
public static int distinctIds(int[] arr, int m)
{
Dictionary<int, int> mp
= new Dictionary<int, int>();
// Store frequency of elements
foreach(int x in arr)
{
if (mp.ContainsKey(x)) {
mp[x]++;
}
else {
mp[x] = 1;
}
}
List<int> freq = new List<int>(mp.Values);
int k = freq.Count;
// Repeatedly remove minimum frequency
while (m > 0) {
int mn = int.MaxValue;
int idx = -1;
// Linear search for minimum frequency
for (int i = 0; i < k; i++) {
if (freq[i] > 0 && freq[i] < mn) {
mn = freq[i];
idx = i;
}
}
// Remove current minimum frequency
if (idx != -1 && mn <= m) {
m -= mn;
freq[idx] = 0;
}
else {
break;
}
}
int res = 0;
// Count remaining distinct elements
foreach(int x in freq)
{
if (x > 0) {
res++;
}
}
return res;
}
public static void Main()
{
int[] arr = { 2, 4, 1, 5, 3, 5, 1, 3 };
int m = 2;
int res = distinctIds(arr, m);
Console.WriteLine(res);
}
}
function distinctIds(arr, m)
{
let mp = new Map();
// Store frequency of elements
for (let x of arr) {
if (mp.has(x)) {
mp.set(x, mp.get(x) + 1);
}
else {
mp.set(x, 1);
}
}
let freq = Array.from(mp.values());
let k = freq.length;
// Repeatedly remove minimum frequency
while (m > 0) {
let mn = Infinity;
let idx = -1;
// Linear search for minimum frequency
for (let i = 0; i < k; i++) {
if (freq[i] > 0 && freq[i] < mn) {
mn = freq[i];
idx = i;
}
}
// Remove current minimum frequency
if (idx !== -1 && mn <= m) {
m -= mn;
freq[idx] = 0;
}
else {
break;
}
}
let res = 0;
// Count remaining distinct elements
for (let x of freq) {
if (x > 0) {
res++;
}
}
return res;
}
// Driver code
let arr = [ 2, 4, 1, 5, 3, 5, 1, 3 ];
let m = 2;
let res = distinctIds(arr, m);
console.log(res);
Output
3
[Better Approach] Using Hash Map and Sorting - O(n + k log k) Time O(k) Space
The idea is to first count the frequency of each element and store it in a list. Since removing all occurrences of a number removes one distinct element, we sort the frequencies in ascending order and greedily remove the smallest ones first. We keep subtracting frequencies from
mwhile it is possible, reducing the number of distinct elements each time a full group is removed. The remaining count of frequencies gives the minimum number of distinct elements left.
#include <bits/stdc++.h>
using namespace std;
// Function to minimize distinct elements
int distinctIds(vector<int> &arr, int m)
{
unordered_map<int, int> mp;
// Store frequency of elements
for (int x : arr)
{
mp[x]++;
}
vector<int> freq;
// Store frequencies
for (auto it : mp)
{
freq.push_back(it.second);
}
// Sort frequencies
sort(freq.begin(), freq.end());
int res = freq.size();
// Remove smaller frequencies first
for (int x : freq)
{
if (x <= m)
{
m -= x;
res--;
}
else
{
break;
}
}
return res;
}
// Driver code
int main()
{
vector<int> arr = {2, 4, 1, 5, 3, 5, 1, 3};
int m = 2;
int res = distinctIds(arr, m);
cout << res;
return 0;
}
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
// Function to minimize distinct elements
public class GfG {
public static int distinctIds(int[] arr, int m)
{
Map<Integer, Integer> mp = new HashMap<>();
// Store frequency of elements
for (int x : arr) {
mp.put(x, mp.getOrDefault(x, 0) + 1);
}
int[] freq = new int[mp.size()];
int index = 0;
// Store frequencies
for (int val : mp.values()) {
freq[index++] = val;
}
// Sort frequencies
Arrays.sort(freq);
int res = freq.length;
// Remove smaller frequencies first
for (int x : freq) {
if (x <= m) {
m -= x;
res--;
}
else {
break;
}
}
return res;
}
// Driver code
public static void main(String[] args)
{
int[] arr = { 2, 4, 1, 5, 3, 5, 1, 3 };
int m = 2;
int res = distinctIds(arr, m);
System.out.println(res);
}
}
from collections import Counter
import operator
# Function to minimize distinct elements
def distinctIds(arr, m):
mp = Counter(arr)
# Store frequencies
freq = list(mp.values())
# Sort frequencies
freq.sort()
res = len(freq)
# Remove smaller frequencies first
for x in freq:
if x <= m:
m -= x
res -= 1
else:
break
return res
# Driver code
if __name__ == "__main__":
arr = [2, 4, 1, 5, 3, 5, 1, 3]
m = 2
res = distinctIds(arr, m)
print(res)
using System;
using System.Collections.Generic;
using System.Linq;
// Function to minimize distinct elements
public class GfG {
public static int distinctIds(int[] arr, int m)
{
Dictionary<int, int> mp
= new Dictionary<int, int>();
// Store frequency of elements
foreach(int x in arr)
{
if (mp.ContainsKey(x)) {
mp[x]++;
}
else {
mp[x] = 1;
}
}
int[] freq = new int[mp.Count];
int index = 0;
// Store frequencies
foreach(int val in mp.Values)
{
freq[index++] = val;
}
// Sort frequencies
Array.Sort(freq);
int res = freq.Length;
// Remove smaller frequencies first
foreach(int x in freq)
{
if (x <= m) {
m -= x;
res--;
}
else {
break;
}
}
return res;
}
// Driver code
public static void Main()
{
int[] arr = { 2, 4, 1, 5, 3, 5, 1, 3 };
int m = 2;
int res = distinctIds(arr, m);
Console.WriteLine(res);
}
}
// Function to minimize distinct elements
function distinctIds(arr, m) {
let mp = new Map();
// Store frequency of elements
for (let x of arr) {
if (mp.has(x)) {
mp.set(x, mp.get(x) + 1);
} else {
mp.set(x, 1);
}
}
let freq = [];
// Store frequencies
for (let val of mp.values()) {
freq.push(val);
}
// Sort frequencies
freq.sort((a, b) => a - b);
let res = freq.length;
// Remove smaller frequencies first
for (let x of freq) {
if (x <= m) {
m -= x;
res--;
} else {
break;
}
}
return res;
}
// Driver code
let arr = [2, 4, 1, 5, 3, 5, 1, 3];
let m = 2;
let res = distinctIds(arr, m);
console.log(res);
Output
3
[Expected Approach] Using Greedy and Frequency Counting - O(n) Time O(n) Space
The idea is to minimize distinct elements by removing
mitems optimally. First, we count the frequency of each element. Since removing all occurrences of an element removes one distinct value, we greedily target elements with the smallest frequencies first because they cost the least deletions to eliminate. We sort (or bucket) frequencies and keep removing the smallest ones whilemallows. Each full removal of a frequency reduces the distinct count by one. The remaining number of frequencies represents the minimum distinct elements left.
Let us understand with example:
Input: arr[] = [2, 4, 1, 5, 3, 5, 1, 3], m = 2
- Frequencies stored in map: [2:1, 4:1, 1:2, 5:2, 3:2]
- Bucket array stores count of frequencies: bucket[1] = 2, bucket[2] = 3
- Initially distinct elements res = 5
- For frequency 1, remove element 2 completely -> m = 1, res = 4;
- remove element 4 completely -> m = 0, res = 3
- Since m = 0, stop processing. Remaining distinct elements are [1, 3, 5].
So, Output is 3
#include <bits/stdc++.h>
using namespace std;
// Function to find minimum number of distinct elements
// after removing exactly m elements
int distinctIds(vector<int> &arr, int m)
{
unordered_map<int, int> mp;
// Store frequency of each element
for (int x : arr)
mp[x]++;
int n = arr.size();
// Create a bucket where index represents frequency
// bucket[i] = number of elements having frequency i
vector<int> bucket(n + 1, 0);
for (auto it : mp)
{
bucket[it.second]++;
}
// Initially all distinct elements are present
int res = mp.size();
// Greedily remove elements with smallest frequency first
// because they reduce distinct count with minimum removals
for (int i = 1; i <= n && m > 0; i++)
{
// While we still have elements with frequency i
// and enough m to remove them completely
while (bucket[i] > 0 && m >= i)
{
// remove all occurrences of one element
m -= i;
// one element removed from this frequency group
bucket[i]--;
// decrease distinct count
res--;
}
}
// Return remaining distinct elements
return res;
}
// Driver code
int main()
{
vector<int> arr = {2, 4, 1, 5, 3, 5, 1, 3};
int m = 2;
cout << distinctIds(arr, m);
return 0;
}
import java.util.*;
class GfG {
// Function to find minimum number of distinct elements
// after removing exactly m elements
static int distinctIds(int[] arr, int m)
{
HashMap<Integer, Integer> mp = new HashMap<>();
// Store frequency of each element
for (int x : arr) {
mp.put(x, mp.getOrDefault(x, 0) + 1);
}
int n = arr.length;
// Create a bucket where index represents frequency
// bucket[i] = number of elements having frequency i
int[] bucket = new int[n + 1];
for (int freq : mp.values()) {
bucket[freq]++;
}
// Initially all distinct elements are present
int res = mp.size();
// Greedily remove elements with smallest frequency
// first because they reduce distinct count with
// minimum removals
for (int i = 1; i <= n && m > 0; i++) {
// While we still have elements with frequency i
// and enough m to remove them completely
while (bucket[i] > 0 && m >= i) {
// remove all occurrences of one element
m -= i;
// one element removed from this frequency
// group
bucket[i]--;
// decrease distinct count
res--;
}
}
// Return remaining distinct elements
return res;
}
// Driver code
public static void main(String[] args)
{
int[] arr = { 2, 4, 1, 5, 3, 5, 1, 3 };
int m = 2;
System.out.println(distinctIds(arr, m));
}
}
from collections import defaultdict
# Function to find minimum number of distinct elements
# after removing exactly m elements
def distinctIds(arr, m):
mp = defaultdict(int)
# Store frequency of each element
for x in arr:
mp[x] += 1
n = len(arr)
# Create a bucket where index represents frequency
# bucket[i] = number of elements having frequency i
bucket = [0] * (n + 1)
for freq in mp.values():
bucket[freq] += 1
# Initially all distinct elements are present
res = len(mp)
# Greedily remove elements with smallest frequency first
# because they reduce distinct count with minimum removals
for i in range(1, n + 1):
while bucket[i] > 0 and m >= i:
# remove all occurrences of one element
m -= i
# one element removed from this frequency group
bucket[i] -= 1
# decrease distinct count
res -= 1
# Return remaining distinct elements
return res
# Driver code
if __name__ == "__main__":
arr = [2, 4, 1, 5, 3, 5, 1, 3]
m = 2
res = distinctIds(arr, m)
print(res)
using System;
using System.Collections.Generic;
class GfG {
// Function to find minimum number of distinct elements
// after removing exactly m elements
static int distinctIds(int[] arr, int m)
{
Dictionary<int, int> mp
= new Dictionary<int, int>();
// Store frequency of each element
foreach(int x in arr)
{
if (mp.ContainsKey(x))
mp[x]++;
else
mp[x] = 1;
}
int n = arr.Length;
// Create a bucket where index represents frequency
// bucket[i] = number of elements having frequency i
int[] bucket = new int[n + 1];
foreach(var it in mp) { bucket[it.Value]++; }
// Initially all distinct elements are present
int res = mp.Count;
// Greedily remove elements with smallest frequency
// first because they reduce distinct count with
// minimum removals
for (int i = 1; i <= n && m > 0; i++) {
// While we still have elements with frequency i
// and enough m to remove them completely
while (bucket[i] > 0 && m >= i) {
// remove all occurrences of one element
m -= i;
// one element removed from this frequency
// group
bucket[i]--;
// decrease distinct count
res--;
}
}
// Return remaining distinct elements
return res;
}
// Driver code
static void Main()
{
int[] arr = { 2, 4, 1, 5, 3, 5, 1, 3 };
int m = 2;
Console.WriteLine(distinctIds(arr, m));
}
}
// Function to find minimum number of distinct elements
// after removing exactly m elements
function distinctIds(arr, m)
{
const mp = new Map();
// Store frequency of each element
for (const x of arr) {
if (mp.has(x)) {
mp.set(x, mp.get(x) + 1);
}
else {
mp.set(x, 1);
}
}
const n = arr.length;
// Create a bucket where index represents frequency
// bucket[i] = number of elements having frequency i
const bucket = new Array(n + 1).fill(0);
for (const freq of mp.values()) {
bucket[freq]++;
}
// Initially all distinct elements are present
let res = mp.size;
// Greedily remove elements with smallest frequency
// first because they reduce distinct count with minimum
// removals
for (let i = 1; i <= n && m > 0; i++) {
while (bucket[i] > 0 && m >= i) {
// remove all occurrences of one element
m -= i;
// one element removed from this frequency group
bucket[i]--;
// decrease distinct count
res--;
}
}
// Return remaining distinct elements
return res;
}
// Driver code
const arr = [ 2, 4, 1, 5, 3, 5, 1, 3 ];
const m = 2;
console.log(distinctIds(arr, m));
Output
3