方法很好想,要么暴力排序,归并,堆排都能满足O(nlogn)的要求。
我第一次想到的就是,用哈希统计一下数字,然后重载排一下序,顺序放入集合里就行。
这次用的是最小堆,主要学习一下PriorityQueue,是基于优先级堆的无界优先级queue
Modifier and Type | Method and Description |
---|---|
boolean | add(E e) 将指定的元素插入到此优先级队列中。 |
void | clear() 从此优先级队列中删除所有元素。 |
Comparator | comparator() 返回用于为了在这个队列中的元素,或比较null 如果此队列根据所述排序natural ordering的元素。 |
boolean | contains(Object o) 如果此队列包含指定的元素,则返回 true 。 |
Iterator | iterator() 返回此队列中的元素的迭代器。 |
boolean | offer(E e) 将指定的元素插入到此优先级队列中。 |
E | peek() 检索但不删除此队列的头,如果此队列为空,则返回 null 。 |
E | poll() 检索并删除此队列的头,如果此队列为空,则返回 null 。 |
boolean | remove(Object o) 从该队列中删除指定元素的单个实例(如果存在)。 |
int | size() 返回此集合中的元素数。 |
Object[] | toArray() 返回一个包含此队列中所有元素的数组。 |
T[] | toArray(T[] a) 返回一个包含此队列中所有元素的数组; 返回的数组的运行时类型是指定数组的运行时类型。 |
public class Main {
public static void main(String[] args) {
int n = 5;
Solution solution = new Solution();
System.out.println(solution.topKFrequent(new int[]{1,1,1,2,2,3}, 2));
}
}
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
HashMap<Integer, Integer> hs = new HashMap<Integer, Integer>();
//统计每一个数出现的次数
for (int num : nums) {
if(hs.containsKey(num)) {
hs.put(num, hs.get(num)+1);
}else {
hs.put(num, 1);
}
}
//因为返回顺序没有要求,可以维护一个最小堆
PriorityQueue<Integer> pq = new PriorityQueue<Integer>(
new Comparator<Integer>() {
//重写比较方法,按照哈希的value大小排序
@Override
public int compare(Integer o1, Integer o2) {
return hs.get(o1) - hs.get(o2);
}
});
for (Integer key : hs.keySet()) {
if (pq.size() < k) { //维护堆的大小为k
pq.add(key);
} else if (hs.get(key) > hs.get(pq.peek())) {//如果当前堆的大小超过k,并且当前遍历到的value值大于堆中最小的value值
pq.remove();
pq.add(key);
}
}
List<Integer> list = new LinkedList<Integer>();
while (!pq.isEmpty()) {
//System.out.println(pq.peek());
list.add(pq.remove()); //remove返回
}
return list;
}
}s
以1,1,1,2,2,3为例。
有三个键值对<1,3>,<2,1>, < 3,1>,最终优先队列从队首到队尾的元素为:2,1
按照value大小排序,2的value较小,所以排在前面(维护的是最小堆)。