题目:
给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序排序。
思路:
1,Hash提取字符频次
2,构建最小堆,然后动态的添加、删除队列首元素直至最后的堆的数据
3,将堆中的数据取出,然后反转一下就行
代码如下:
public static List<String> topKFrequent(String[] words, int k) {
// 1 利用哈希提取频次
HashMap<String, Integer> map = new HashMap();
for(String str:words){
map.put(str,map.getOrDefault(str,0)+1);
}
// 建小堆
PriorityQueue<String> queue = new PriorityQueue((a,b)->{
if(map.get(a).equals(map.get(b))){
// 如果频次一样,则还需要按照字典顺序排序
// 注意,这里的b、a顺序不能搞反,原因在于在堆内中、频次相同的,按照字典顺序靠前优先排序,字典值靠前意味着ASCLL码越小
// 而compareTo函数比较的就是ASCLL码,a.compareTo(b):表示升序,b.compareTo(a):表示降序
return ((String)b).compareTo((String)a);
}else{
return map.get(a) - map.get(b);
}
});
// 将数据放入堆中
for(String str: map.keySet() ){
if(queue.size()<k){
queue.offer(str);
continue;
}
// 堆满K个元素之后,后续加入的节点频次必须高于或者等于队列首元素的频次
// 考虑到频次相等的时还需要按字典顺序排序的情况(注意,这个选择字典靠前的(ASCLL码较小的))
if(map.get(queue.peek())<=map.get(str)){
if(map.get(queue.peek())==map.get(str)){
if(str.compareTo(queue.peek())<0) {
queue.poll();
queue.offer(str);
}
continue;
}
queue.poll();
queue.offer(str);
}
}
List<String> strList = new ArrayList<>();
while(!queue.isEmpty()){
strList.add(queue.poll());
}
Collections.reverse(strList);
return strList;
}