题干
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
说明:
你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
想法
找K频率的元素,是经典的hashmap的用法。
O(n log n) 是在暗示使用堆
补充
在这儿使用 PriorityQueue的方法:
下方代码分别实现了大顶堆,小顶堆。其中小顶堆是默认的compare方法,大顶堆是重写了compare方法
PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>(); //小顶堆,默认容量为11
PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(11,new Comparator<Integer>(){ //大顶堆,容量11
@Override
public int compare(Integer i1,Integer i2){
return i2-i1;
}
});
这个compare方法几乎是使用优先队列时必重写的方法,这个方法叫匿名实现比较器,也就是这个优先队列默认是通过队列里的数的大小从小到大排序的。如果想要其他的排序方式就需要重写这个compare方法。
以下是
PriorityQueue的常用方法有:
poll(),offer(Object),size(),peek()等。
啊插入方法(offer()、poll()、remove() 、add() 方法)时间复杂度为O(log(n)) ;
remove(Object) 和 contains(Object) 时间复杂度为O(n);
检索方法(peek、element 和 size)时间复杂度为常量。
PriorityQueue的API文档说明:
构造方法摘要
PriorityQueue()
使用默认的初始容量(11)创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。
PriorityQueue(Collection<? extends E> c)
创建包含指定 collection 中元素的 PriorityQueue。
PriorityQueue(int initialCapacity)
使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。
PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
使用指定的初始容量创建一个 PriorityQueue,并根据指定的比较器对元素进行排序。
PriorityQueue(PriorityQueue<? extends E> c)
创建包含指定优先级队列元素的 PriorityQueue。
PriorityQueue(SortedSet<? extends E> c)
创建包含指定有序 set 元素的 PriorityQueue。
方法摘要 | |
---|---|
boolean | add(E e) 将指定的元素插入此优先级队列。 |
void | clear() 从此优先级队列中移除所有元素。 |
Comparator<? superE> | comparator() 返回用来对此队列中的元素进行排序的比较器;如果此队列根据其元素的自然顺序进行排序,则返回 null。 |
boolean | contains(Object o) 如果此队列包含指定的元素,则返回 true。 |
Iterator | iterator() 返回在此队列中的元素上进行迭代的迭代器。 |
boolean | offer(E e) 将指定的元素插入此优先级队列。 |
E | peek() 获取但不移除此队列的头;如果此队列为空,则返回 null。 |
E | poll() 获取并移除此队列的头,如果此队列为空,则返回 null。 |
boolean | remove(Object o) 从此队列中移除指定元素的单个实例(如果存在)。 |
int | size() 返回此 collection 中的元素数。 |
Object[] | toArray() 返回一个包含此队列所有元素的数组。 |
T[] | toArray(T[] a) 返回一个包含此队列所有元素的数组;返回数组的运行时类型是指定数组的类型。 |
从类 java.util.AbstractQueue 继承的方法
addAll, element, remove
从类 java.util.AbstractCollection 继承的方法
containsAll, isEmpty, removeAll, retainAll, toString
从类 java.lang.Object 继承的方法
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait,wait
从接口 java.util.Collection 继承的方法
containsAll, equals, hashCode, isEmpty, removeAll, retainAll
Java的Map中的map.keySet()方法
该方法返回map中所有key值的列表。
参考https://blog.csdn.net/qq_30507287/article/details/80488512
代码
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
if(nums==null || nums.length == 0)
return new ArrayList();
// 使用HashMap,统计每个元素出现的次数,元素为键,元素出现的次数为值
HashMap<Integer,Integer> map = new HashMap();
for(int num : nums){
if (map.containsKey(num)) {
//重复出现
map.put(num, map.get(num) + 1);
} else {
map.put(num, 1);
}
}
// 遍历map,用最小堆保存频率最大的k个元素
PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return map.get(a) - map.get(b);
}
});
//如果pq还没被装满,那么直接装,装满了如果现在取到的这个元素比pq的最小值大,那么就换掉它
for (Integer key : map.keySet()) {
if (pq.size() < k) {
pq.add(key);
} else if (map.get(key) > map.get(pq.peek())) {
pq.poll();
pq.add(key);
}
}
// 取出最小堆中的元素
List<Integer> res = new ArrayList<>();
while (!pq.isEmpty()) {
res.add(pq.poll());
}
return res;
}
}
代码参考
https://www.cnblogs.com/yanhowever/p/11649479.html
大佬代码
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
if(nums==null || nums.length == 0)
return new ArrayList();
ArrayList<Integer> countList = new ArrayList<Integer>();
List<Integer> res = new ArrayList();
HashMap<Integer,ArrayList<Integer>> map = new HashMap<Integer,ArrayList<Integer>>();
if (nums.length == 1) {
res.add(nums[0]);
return res;
}
Arrays.sort(nums);
int count = 1;
int start = nums[0];
for(int i = 1; i < nums.length; i++) {
if (start != nums[i]) {
ArrayList<Integer> itemList = map.get(count);
if (itemList == null) {
countList.add(count);
ArrayList<Integer> numberList = new ArrayList<Integer>();
numberList.add(start);
map.put(count, numberList);
} else {
itemList.add(start);
}
start = nums[i];
count = 0;
}
count ++;
}
ArrayList<Integer> itemList = map.get(count);
if (itemList == null) {
countList.add(count);
ArrayList<Integer> numberList = new ArrayList<Integer>();
numberList.add(start);
map.put(count, numberList);
} else {
itemList.add(start);
}
countList.sort(null);
int idx = countList.size() - 1;
while(k>0){
for(int j: map.get(countList.get(idx))){
res.add(j);
k--;
if(k<=0)
break;
}
idx--;
}
return res;
}
}