from collections import Counter
class Solution:
def minSetSize(self, arr):
freq = Counter(arr)
counts = sorted(freq.values(), reverse=True)
removed = 0
res = 0
half = len(arr) // 2
for c in counts:
removed += c
res += 1
if removed >= half:
return res
#include <vector>
#include <unordered_map>
#include <algorithm>
class Solution {
public:
int minSetSize(std::vector<int>& arr) {
std::unordered_map<int, int> freq;
for (int n : arr) freq[n]++;
std::vector<int> counts;
for (auto &p : freq) counts.push_back(p.second);
std::sort(counts.rbegin(), counts.rend());
int removed = 0, res = 0, half = arr.size() / 2;
for (int c : counts) {
removed += c;
res++;
if (removed >= half) return res;
}
return res;
}
};
import java.util.*;
class Solution {
public int minSetSize(int[] arr) {
Map<Integer, Integer> freq = new HashMap<>();
for (int n : arr) freq.put(n, freq.getOrDefault(n, 0) + 1);
List<Integer> counts = new ArrayList<>(freq.values());
counts.sort(Collections.reverseOrder());
int removed = 0, res = 0, half = arr.length / 2;
for (int c : counts) {
removed += c;
res++;
if (removed >= half) return res;
}
return res;
}
}
var minSetSize = function(arr) {
let freq = {};
for (let n of arr) freq[n] = (freq[n] || 0) + 1;
let counts = Object.values(freq).sort((a, b) => b - a);
let removed = 0, res = 0, half = arr.length / 2;
for (let c of counts) {
removed += c;
res++;
if (removed >= half) return res;
}
};
You are given an integer array arr
. Your task is to remove as few elements as possible from arr
so that at least half of the elements are removed.
However, you can only remove all occurrences of a chosen integer at a time (i.e., you remove entire "sets" of the same value).
Return the minimum number of unique integers you need to choose so that removing all their occurrences reduces the size of arr
by at least half.
Key constraints:
At first, it might seem like you have to try all possible combinations of numbers to remove, but this would be very slow for large arrays.
The key insight is that removing numbers that appear most frequently will reduce the array size the fastest. So, instead of brute-forcing all possibilities, we should focus on the numbers with the highest counts.
This leads to a greedy approach: always remove the number with the highest frequency next, and keep track of how many elements have been removed so far.
This is much more efficient than trying every possible subset of numbers.
The solution can be broken down into the following steps:
arr
. We use a hash map (dictionary) for this, since looking up and updating counts is fast (O(1) time per operation).
This approach is efficient because it only requires counting, sorting, and a single pass through the sorted frequencies.
Let's say arr = [3,3,3,3,5,5,5,2,2,7]
.
This means we only need to remove two unique numbers (3 and 5) to reduce the array size by at least half.
Brute-force approach:
arr
.This is efficient and suitable for large arrays.
To solve "Reduce Array Size to The Half", we count how many times each number appears, then repeatedly remove all occurrences of the most frequent numbers until we've removed at least half the array.
The greedy approach works because removing the most frequent numbers is always optimal for minimizing the number of sets chosen. This method is both simple and efficient, making it a great example of using counting and sorting to solve a problem optimally.