一、题目
二、思路
/**
* 哈希表+堆(优先队列)
* 题目要求小于nlogn的时间,用哈希表+排序的话就是nlogn,肯定不行
* 这里先用哈希表统计每个数字出现的次数,然后用优先队列去操作,
* 当队列中元素个数小于k时,直接入队;
* 队列元素个数大于k时,拿队首元素和入队元素比较,如果队首元素大于入队元素,
* 说明当前队列所有元素都大于入队元素,直接进行下一个,如果队首元素小于入队元素,
* 那么队首元素出队,入队元素入队即可。
* 哈希表记录元素出现个数,每个元素O(1),n个元素O(n),
* 堆的大小最多为k,k<=n,每次操作需要O(logk),n个元素就是O(nlogk),满足题意
*/
三、代码
public int[] topKFrequent(int[] nums, int k) {
//统计元素出现次数
Map<Integer, Integer> counts = new HashMap<>();
for (int n : nums) {
counts.put(n, counts.getOrDefault(n, 0) + 1);
}
//入队
PriorityQueue<int[]> priorityQueue = new PriorityQueue<>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) { //提供自定义比较器
return o1[1] - o2[1];
}
});
for (Map.Entry<Integer, Integer> entry : counts.entrySet()) {
int key = entry.getKey(), value = entry.getValue();
if (priorityQueue.size() < k) { //队列不满时
priorityQueue.add(new int[]{key, value});
} else { //队列满时
if (priorityQueue.peek()[1] < value) { //入队值比队首值大
priorityQueue.poll(); //队首出队
priorityQueue.add(new int[]{key, value}); //当前元素入队
}
}
}
//返回结果
int[] res = new int[k];
for (int i = 0; i < k; i++) {
res[i] = priorityQueue.poll()[0]; //接收的是key
}
return res;
}