题目描述
Given a non-empty array of integers, return the k most frequent elements.
Example 1:
Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]
Example 2:
Input: nums = [1], k = 1
Output: [1]
Note:
- You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
- Your algorithm's time complexity must be better than O(n log n), where n is the array's size.
本文思路来源:https://www.cnblogs.com/xugenpeng/p/9950007.html
这篇博客总结的很好,所以这里只做了一下搬运工。
思路一
将数组元素按照频率有高到低排序,然后取出前K个。
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
//统计元素频率
Map<Integer,Integer> map=new HashMap<>();
for(int num:nums){
map.put(num,map.getOrDefault(num,0)+1);
}
//对元素按照频率进行排序
List<Map.Entry<Integer,Integer>> list=new ArrayList<>(map.entrySet());
Collections.sort(list,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();
}
});
//取出前K个元素
int count=0;
List<Integer> ret=new ArrayList<>();
for(Map.Entry<Integer,Integer> entry:list){
ret.add(entry.getKey());
count++;
if(count>=k){
break;
}
}
return ret;
}
}
思路二:最小堆
这里我们可以联系到之前做过的剑指offer中最小的K个数的方法,对于海量数据中最小的K个数选用最大堆来保存。
这里我们选取最小堆,堆中保留频率最大的K 个数,堆顶元素最小,若新来的元素比这个最小的频率大,则替换堆顶元素。
import java.util.*;
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
//统计元素频率
Map<Integer,Integer> map=new HashMap<>();
for(int num:nums){
map.put(num,map.getOrDefault(num,0)+1);
}
//遍历map,用最小堆保存频率前k大的元素
PriorityQueue<Integer> minQueue=new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return map.get(o1)-map.get(o2);
}
});
for (Integer key:map.keySet()){
if(minQueue.size()<k){
minQueue.add(key);
}else if(map.get(key)>map.get(minQueue.peek())){
//新来的元素频率大于堆顶元素的频率
minQueue.remove();
minQueue.add(key);
}
}
//取出最小堆中的元素
List<Integer> ret=new ArrayList<>();
while(!minQueue.isEmpty()){
ret.add(minQueue.remove());// 从此队列中移除指定元素的单个实例(如果存在)。
}
return ret;
}
}
思路三:桶排序
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
//统计元素频次
Map<Integer,Integer> map=new HashMap<>();
for(int num:nums){
map.put(num,map.getOrDefault(num,0)+1);
}
//桶排序
List<Integer>[] bucket=new List[nums.length+1];
for(Integer key:map.keySet()){
int freq=map.get(key);
if(bucket[freq]==null){
bucket[freq]=new ArrayList<>();
}
bucket[freq].add(key);
}
//按照频数从高到低取出元素
List<Integer> ret=new ArrayList<>();
for(int i=nums.length;i>=0&&ret.size()<k;i--){
if(bucket[i]!=null){
ret.addAll(bucket[i]);
}
}
return ret;
}
}