开始不会做,因为要用到很多map、list、collection的方法和性质
第一个解答中排序用以下三个句子都行:
Collections.sort(list, Collections.reverseOrder());
list.sort((a, b) -> b - a);
list.sort(Collections.reverseOrder());
/**
* 最简洁的代码
* 巧妙利用Collections类的sort()方法,将数字出现次数排序,从出现次数多的往小的加,直到累加超过arr长度的一半
*/
class Solution {
public int minSetSize(int[] arr) {
HashMap<Integer, Integer> map = new HashMap<>(); // 用map统计各个数字出现的次数
for (int i : arr)
map.put(i, map.getOrDefault(i, 0) + 1);
ArrayList<Integer> list = new ArrayList<>(map.values()); // 用list存放各个数字出现的次数
Collections.sort(list, Collections.reverseOrder()); // 同list.sort((a, b) -> b - a),同list.sort(Collections.reverseOrder()),将出现的次数从高到低排序
int half = arr.length / 2, idx = 0; // 直接用arr.length/2是因为题目要求arr.length是偶数
while (half > 0)
half -= list.get(idx++);
return idx;
}
}
/**
* 不需要对各数字出现次数组成的数组或list排序
* 时间效率高,Runtime: 27 ms, faster than 90.68%
* 但代码比较复杂、空间消耗多一点
*/
class Solution {
public int minSetSize(int[] arr) {
if (arr.length <= 2)
return 1;
HashMap<Integer, Integer> map = new HashMap<>(); // 数字与出现次数的映射
int[] values = new int[arr.length + 1]; // 下标为数字出现次数的数组
for (int i : arr) // 计数每个数字出现的次数
map.put(i, map.getOrDefault(i, 0) + 1);
for (int i : map.values()) // 统计相同次数的数字个数
values[i]++;
int target = arr.length / 2, res = 0;
for (int i = arr.length; i >= 0 && target > 0; i--) {
if (values[i] == 0) // 没有出现i次的数字
continue;
while (values[i] > 0 && target > 0) {
target -= i;
res++;
values[i] -= 1;
}
}
return res;
}
}