今天继续哈,写的还是比较简单的一个题,哈希表和堆排序,要多多熟悉java的数据结构。
题目
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
例如,
给定数组 [1,1,1,2,2,3]
, 和 k = 2,返回 [1,2]
。
注意:
- 你可以假设给定的 k 总是合理的,1 ≤ k ≤ 数组中不相同的元素的个数。
- 你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
分析
看到给出一个数组,输出频率最高的第一反应就是哈希表嘛, 因为输出频率前k高的元素,所以要进行一次排序,注意里要求,时间复杂度必须优于O(n log n),堆排序是时间复杂度为O(n log n),这样就用了优先队列PriorityQueue。
首先遍历数组,将数组中的数字和出现的对应频率存入map中,这里可以把map中的键值对分散为一个一个的Map.Entry<K,V>,对value排序存放入堆中,最后将前k大的出队。
java的优先队列默认为小顶堆,在创建堆的时候要写一下比较器,通过entry的value值进行降序排序。
代码
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
List<Integer> list = new ArrayList<>();
PriorityQueue<Map.Entry<Integer,Integer>> pq = new PriorityQueue<>(new Comparator<Map.Entry<Integer, Integer>>() {
@Override
public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
return o2.getValue()-o1.getValue();
}
});
Map<Integer,Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++)
if (map.containsKey(nums[i]))
map.put(nums[i],map.get(nums[i])+1);
else
map.put(nums[i],1);
Set<Map.Entry<Integer,Integer>> set = map.entrySet();
for (Map.Entry<Integer,Integer> entry : set)
pq.add(entry);
for (int i = 0; i < k; i++)
list.add(pq.poll().getKey());
return list;
}
}
因为一开始没有注意到Map.Entry这个的存在,想要在优先队列中存放键值对可是不知道使用什么数据结构,之后看了结题报告才明白,所以要好好熟悉数据结构。
Map.Entry
映射项(键-值对)。Map.entrySet 方法返回映射的 collection 视图,其中的元素属于此类。获得映射项引用的唯一 方法是通过此 collection 视图的迭代器来实现。这些 Map.Entry 对象仅 在迭代期间有效;更确切地讲,如果在迭代器返回项之后修改了底层映射,则某些映射项的行为是不确定的,除了通过 setValue 在映射项上执行操作之外。