
Problem Statement
In this problem, you are provided with an integer array arr
. Your task is to determine the smallest number of unique integers that can be selected from arr
such that when all occurrences of these chosen integers are removed from the array, the remaining elements of the array are reduced to half of its original size or less.
Examples
Example 1
Input:
arr = [3,3,3,3,5,5,5,2,2,7]
Output:
2
Explanation:
Choosing {3,7} will make the new array [5,5,5,2,2] which has size 5 (i.e equal to half of the size of the old array). Possible sets of size 2 are {3,5},{3,2},{5,2}. Choosing set {2,7} is not possible as it will make the new array [3,3,3,3,5,5,5] which has a size greater than half of the size of the old array.
Example 2
Input:
arr = [7,7,7,7,7,7]
Output:
1
Explanation:
The only possible set you can choose is {7}. This will make the new array empty.
Constraints
2 <= arr.length <= 105
arr.length
is even.1 <= arr[i] <= 105
Approach and Intuition
- First, understand the length of the array,
n
, and calculate half the length because our target is to reduce the array to at least half its size. - Create a frequency count of each integer in the array. This is crucial as the strategy heavily relies on maximising the removal of elements by focusing on the most frequent elements first.
- Collect the frequency counts into a list and sort this list in descending order. The rationale here is that by removing the most frequent elements, we can reduce the size of the array more quickly.
- Traverse through this sorted list, maintaining a cumulative sum of the frequencies:
- For each element's frequency in the list, add it to a running total.
- Check if the running total meets or exceeds half of the array's length. The count of numbers added to this running total, up to this point, will be the smallest set of unique integers that fulfills the condition of reducing the array's size to half or less.
- Return the number of unique integers that make up this smallest set, as this is the solution to the problem.
For example, consider the array [3,3,3,3,5,5,5,2,2,7]
:
- Calculating frequency yields:
3
occurs 4 times,5
occurs 3 times,2
occurs 2 times, and7
once. - Sorting by frequency in descending order gives
[4, 3, 2, 1]
. - A cumulative count through this sorted list shows that selecting integers with the highest frequencies allows us to reduce the array's total count quickly. Hence,
arr[0] + arr[1]
which are3
and5
respectively may be enough depending on their summed frequencies versus half the array's length.
This approach ensures an efficient way to find out the minimum set size using basic properties of frequency distribution.
Solutions
- Java
- JavaScript
class Solution {
public int minimumSize(int[] array) {
Map<Integer, Integer> frequency = new HashMap<>();
int highestFreq = 0;
for (int value : array) {
if (!frequency.containsKey(value)) {
frequency.put(value, 0);
}
int updatedFreq = frequency.get(value) + 1;
frequency.put(value, updatedFreq);
highestFreq = Math.max(highestFreq, updatedFreq);
}
// Create buckets for frequency counts.
int[] frequencyBuckets = new int[highestFreq + 1];
for (int freq : frequency.values()) {
frequencyBuckets[freq]++;
}
// Calculate required removals.
int resultSize = 0;
int toRemove = array.length / 2;
int currentFreq = highestFreq;
while (toRemove > 0) {
int needed = toRemove / currentFreq;
if (toRemove % currentFreq != 0) {
needed++;
}
int increaseCount = Math.min(frequencyBuckets[currentFreq], needed);
resultSize += increaseCount;
toRemove -= increaseCount * currentFreq;
currentFreq--;
}
return resultSize;
}
}
The solution provided addresses the problem of reducing the size of an array by at least half by removing the least number of unique elements based on their frequencies. Below is the summary of the solution approach implemented in Java:
- Utilize a
HashMap
calledfrequency
to store each unique element of the array as keys and their corresponding counts as values. - Iterate through the given array and update the frequency map with the count of each element. Simultaneously, keep track of the maximum frequency (
highestFreq
) of any single element. - Create an integer array
frequencyBuckets
where the index represents the frequency of elements and each value at that index represents how many elements have that frequency. - Populate
frequencyBuckets
by iterating over thefrequency
values. - To determine the minimum number of unique elements to remove, start from the highest frequency and calculate how many elements of that frequency need to be removed to reduce the array's size by half.
- Keep decrementing the number of elements needed to be removed (
toRemove
) and the current frequency from which elements are being removed (currentFreq
), until the rest of the array size is reduced by at least half. - The value returned by the function,
resultSize
, indicates the minimum set of unique elements that needs to be removed.
This solution effectively maps element frequencies, leverages the counting sort principle via frequency buckets, and utilizes a greedy strategy from the highest frequencies downward to minimize the number of unique elements removed, ensuring the array size is reduced by at least half.
class FrequencyCounter {
_frequencyMap = new Map();
increment(item) {
if (!this._frequencyMap.has(item)) {
this._frequencyMap.set(item, 0);
}
this._frequencyMap.set(item, this._frequencyMap.get(item) + 1);
return this._frequencyMap.get(item);
}
getValues() {
return this._frequencyMap.values();
}
}
var findMinSetSize = function(arr) {
const frequencyCounter = new FrequencyCounter();
let highestFrequency = 0;
for (const element of arr) {
const updatedCount = frequencyCounter.increment(element);
highestFrequency = Math.max(updatedCount, highestFrequency);
}
if (highestFrequency > arr.length / 2) {
return 1;
}
const frequencyBuckets = Array.from({ length: highestFrequency + 1 }, () => 0);
for (const count of frequencyCounter.getValues()) {
frequencyBuckets[count] += 1;
}
let requiredSetSize = 0;
let remainToRemove = Math.floor(arr.length / 2);
let currentHighest = highestFrequency;
while (remainToRemove > 0) {
const needFromBucket = Math.ceil(remainToRemove / currentHighest);
const addToSetSize = Math.min(frequencyBuckets[currentHighest], needFromBucket);
requiredSetSize += addToSetSize;
remainToRemove -= addToSetSize * currentHighest;
currentHighest -= 1;
}
return requiredSetSize;
}
The JavaScript solution for reducing the size of an array to half involves a multi-step process that focuses on counting the frequency of each element and then using this data to determine the minimum set of elements that can represent at least half of the array. Here’s how the solution breaks down:
Define a
FrequencyCounter
class to manage the frequency of each element in the array. This class uses a Map to store elements as keys and their frequencies as values. The class has two methods:increment(item)
: Increases the frequency count of anitem
by one. If the item is not present in the map, it initializes the count.getValues()
: Returns all frequency values from the map.
Write a function
findMinSetSize
that takes an arrayarr
as input and utilizes theFrequencyCounter
to calculate and return the minimum set size that can represent at least half of the elements from the input array.Iterate over each element in the array, updating the frequency of each element using the
increment
method ofFrequencyCounter
. During this iteration, also keep track of thehighestFrequency
of any single element.Immediately return a value of 1 if any single element's frequency exceeds half of the total array length.
Create a frequency distribution array,
frequencyBuckets
, where each index represents how many elements have that frequency.Populate
frequencyBuckets
by iterating over the values from the frequency counter. Each index infrequencyBuckets
accumulates counts of elements that have frequencies corresponding to that index.Determine the required set size (
requiredSetSize
) by evaluating each frequency bucket, starting from the highest. The process continues until half of the array elements are removed. This is done by calculating how many elements are needed from each bucket to meet the requirement of removing half of the array's elements, adjusting the count ofremainToRemove
for each bucket utilized.
By the end of these steps, the result will be the minimum number of different elements needed to make sure that at least half of the array's elements can be discarded by frequency, effectively reducing the array's size by at least half.
No comments yet.