Given an array of integers arr
and an integer k
. Find the least number of unique integers after removing exactly k
elements.
Example 1:
Input: arr = [5,5,4], k = 1 Output: 1 Explanation: Remove the single 4, only 5 is left.Example 2:
Input: arr = [4,3,1,1,3,3,2], k = 3 Output: 2 Explanation: Remove 4, 2 and either one of the two 1s or three 3s. 1 and 3 will be left.
Constraints:
1 <= arr.length <= 10^5
1 <= arr[i] <= 10^9
0 <= k <= arr.length
This problem asks to find the minimum number of unique integers remaining in an array after removing exactly k
elements. The optimal approach involves using a hash table (or dictionary) to count the frequency of each integer and then employing a greedy strategy.
Algorithm:
Frequency Counting: Use a hash table (e.g., Counter
in Python, HashMap
in Java) to count the occurrences of each integer in the input array arr
.
Frequency Sorting: Create a list or array containing the frequencies of each unique integer. Sort this list in ascending order. This is crucial because the greedy strategy prioritizes removing the least frequent elements first.
Greedy Removal: Iterate through the sorted frequency list. For each frequency freq
, subtract freq
from k
.
If k
becomes less than or equal to 0, it means we've removed enough elements. The remaining number of unique integers is the length of the frequency list minus the index of the current frequency.
If we iterate through the entire frequency list and k
is still greater than 0, it means we can remove all the elements, resulting in 0 unique integers remaining.
Code Implementation (Python):
from collections import Counter
class Solution:
def findLeastNumOfUniqueInts(self, arr: List[int], k: int) -> int:
cnt = Counter(arr) # Count frequencies
freqs = sorted(cnt.values()) # Sort frequencies in ascending order
for i, freq in enumerate(freqs):
k -= freq
if k <= 0:
return len(freqs) - i # Return remaining unique integers
return 0 # All elements removed
Code Implementation (Java):
import java.util.*;
class Solution {
public int findLeastNumOfUniqueInts(int[] arr, int k) {
Map<Integer, Integer> cnt = new HashMap<>();
for (int x : arr) {
cnt.put(x, cnt.getOrDefault(x, 0) + 1);
}
List<Integer> freqs = new ArrayList<>(cnt.values());
Collections.sort(freqs);
for (int i = 0; i < freqs.size(); i++) {
k -= freqs.get(i);
if (k <= 0) {
return freqs.size() - i;
}
}
return 0;
}
}
Time Complexity Analysis:
Therefore, the overall time complexity is dominated by the sorting step: O(n log n) in the worst case (when all elements are unique).
Space Complexity Analysis:
The space complexity is O(n) in the worst case (when all elements are unique).
Example Walkthrough:
Let's consider arr = [4,3,1,1,3,3,2]
, k = 3
.
cnt
will be {4:1, 3:3, 1:2, 2:1}
.freqs
will be [1, 1, 2, 3]
after sorting.k
starts at 3.k -= 1
(first 1), k = 2
.k -= 1
(second 1), k = 1
.k -= 2
(2), k = -1
. We stop here because k
is negative.len(freqs) - i = 4 - 3 = 1
. This is incorrect, should be 2. The code has a small bug because it does not handle the case when k becomes less than 0. it should be len(freqs) -i +1
.The corrected Python code should be:
from collections import Counter
class Solution:
def findLeastNumOfUniqueInts(self, arr: List[int], k: int) -> int:
cnt = Counter(arr) # Count frequencies
freqs = sorted(cnt.values()) # Sort frequencies in ascending order
for i, freq in enumerate(freqs):
k -= freq
if k < 0:
return len(freqs) - i # Return remaining unique integers
return 0 # All elements removed