一、题目描述
Given a non-empty array of integers, return the k most frequent elements.
Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]
二、题解
方法一:排序
使用排序算法对元素按照出现频率降序排列,最后取出前 个元素。
/**
* @date: 2/19/2020 5:09 PM
* @Execution info:ms 击败 % 的j,MB 击败 % 的j
*/
public List<Integer> topKFrequent(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
ArrayList<Integer> list = new ArrayList<>(map.keySet());
// Collections.sort(list, new Comparator<Integer>() {
// @Override
// public int compare(Integer o1, Integer o2) {
// return map.get(o2) - map.get(o1);
// }
// });
Collections.sort(list, (e1, e2) -> map.get(e2).compareTo(map.get(e1)));
LinkedList<Integer> resList = new LinkedList<>();
for (int i = 0; i < k; i++) {
resList.add(list.get(i));
}
return resList;
}
复杂度分析
- 时间复杂度: ,
- 空间复杂度: ,
方法二:最小堆
算法
- 使用数组 / HashMap 统计元素的频率。
- 维护一个元素数目为 k 的优先级队列(最小堆)。
- 每次都将即将添加的元素与堆顶元素(堆中频率最小的元素)进行比较。
- 如果比堆顶元素还小,直接扔掉;否则压入堆。
- 最后,前 k 个高频元素就是堆中的 k 个元素。
/**
* @thought:小根堆:维护堆大小不超过 k 即可。
* 检查堆大小是否超过 k,如果超过,弹出堆顶。复杂度是 nlogk
* @date: 2/19/2020 5:09 PM
* @Execution info:16ms 击败 % 的j,MB 击败 5.47% 的j
* @Asymptotic Time Complexity:O()
*/
public List<Integer> topKFrequent1(int[] nums, int k) {
LinkedList<Integer> resList = new LinkedList<>();
HashMap<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
//lambda形式的自定义比较器
PriorityQueue<Integer> pQ = new PriorityQueue<>(
(e1, e2) -> map.get(e1) - map.get(e2)
);
for (Integer key : map.keySet()) {
if (pQ.size() < k) {
pQ.add(key);
} else if (map.get(pQ.peek()) < map.get(key)){
pQ.poll();
pQ.add(key);
}
}
while (!pQ.isEmpty()) {
resList.add(pQ.poll());
}
return resList;
}
复杂度分析
- 时间复杂度:
,map 建立映射需要
时间;建堆需要
。 因此总复杂度为
=
。
- 因为始终存在一个正常数 ,使得 .
- 空间复杂度: ,存储映射需要的存储空间。