题目描述
给你一个整数数组 arr
。你可以从中选出一个整数集合,并删除这些整数在数组中的每次出现。
返回 至少 能删除数组中的一半整数的整数集合的最小大小。
样例
输入:arr = [3,3,3,3,5,5,5,2,2,7]
输出:2
解释:选择 {3,7} 使得结果数组为 [5,5,5,2,2]、长度为 5(原数组长度的一半)。
大小为 2 的可行集合有 {3,5},{3,2},{5,2}。
选择 {2,7} 是不可行的,它的结果数组为 [3,3,3,3,5,5,5],
新数组长度大于原数组的二分之一。
输入:arr = [7,7,7,7,7,7]
输出:1
解释:我们只能选择集合 {7},结果数组为空。
输入:arr = [1,9]
输出:1
输入:arr = [1000,1000,3,7]
输出:1
输入:arr = [1,2,3,4,5,6,7,8,9,10]
输出:5
限制
1 <= arr.length <= 10^5
arr.length
为偶数1 <= arr[i] <= 10^5
算法
(贪心,哈希表,排序) $O(n \log n)$
- 用哈希表统计出每个数字的出现次数,将这些次数存放在一个数组中,然后将数组排序。
- 根据贪心,我们肯定按照次数从多到少的顺序删除。
时间复杂度
- 最坏情况下,每个数字都出现一次,所以时间复杂度为 $O(n \log n)$。
空间复杂度
- 最坏情况下,需要 $O(n)$ 的空间存储每个数字的出现次数。
C++ 代码
class Solution {
public:
int minSetSize(vector<int>& arr) {
unordered_map<int, int> v;
for (int x : arr)
v[x]++;
vector<int> c;
for (const auto &ele : v)
c.push_back(ele.second);
sort(c.begin(), c.end());
int tot = 0;
for (int i = c.size() - 1; i >= 0; i--) {
tot += c[i];
if (2 * tot >= arr.size())
return c.size() - i;
}
return c.size();
}
};