leetcode-347:前K个高频元素集
描述:
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
思路:
- 本题是优先队列的经典问题(在1000000个元素中选出前100名),即在N个元素中选出前k个元素
- 用排序的话,算法复杂度是NlogN
- 使用优先队列,算法复杂度是Nlogk
使用优先队列,维护当前看到的前k个元素,需要使用最小堆;
先给出最开始的代码,然后一步步优化:
(1)先用之前自定义的优先队列来实现:
import java.util.LinkedList;
import java.util.List;
import java.util.TreeMap;
public class Solution {
private class Freq implements Comparable<Freq> {
int e, fre;
public Freq(int e, int fre) {
this.e = e;
this.fre = fre;
}
@Override
public int compareTo(Freq another) {//定义优先级,频次越低,优先级越高
if(this.fre < another.fre) {
return 1;
} else if(this.fre > another.fre) {
return -1;
} else {
return 0;
}
}
}
public List<Integer> topKFrequent(int[] nums, int k) {
//统计频次
TreeMap<Integer, Integer> map = new TreeMap<>();
for(int num : nums) {
if(map.containsKey(num)) {
map.put(num, map.get(num) + 1);
} else {
map.put(num, 1);
}
}
//维护当前看到的前K个元素
PriorityQueue<Freq> pq = new PriorityQueue<>();
for(int key : map.keySet()) {
if(pq.getSize() < k) {
pq.enqueue(new Freq(key, map.get(key)));
} else if(map.get(key) > pq.getFront().fre) {
pq.dequeue();
pq.enqueue(new Freq(key, map.get(key)));
}
}
LinkedList<Integer> res = new LinkedList<>();
while (!pq.isEmpty()) {
res.add(pq.dequeue().e);
}
return res;
}
}
(2)用Java的优先队列(注意Java优先级队列底层默认是最小堆)
import java.util.*;
class Solution {
public class Freq implements Comparable<Freq> {
int e, freq;
public Freq(int e, int freq) {
this.e = e;
this.freq = freq;
}
@Override
public int compareTo(Freq another) {//定义优先级
if(this.freq > another.freq) {
return 1;
} else if(this.freq < another.freq) {
return -1;
} else {
return 0;
}
}
}
public List<Integer> topKFrequent(int[] nums, int k) {
//统计频次
TreeMap<Integer, Integer> map = new TreeMap<>();
for(int num : nums) {
if(map.containsKey(num)) {
map.put(num, map.get(num) + 1);
} else {
map.put(num, 1);
}
}
//维护当前看到的前k个出现频次最高的元素
PriorityQueue<Freq> pq = new PriorityQueue<>();
for(int key : map.keySet()) {
if(pq.size() < k) {
pq.add(new Freq(key, map.get(key)));
} else if(map.get(key) > pq.peek().freq) {
pq.remove();
pq.add(new Freq(key, map.get(key)));
}
}
LinkedList<Integer> res = new LinkedList<>();
while(!pq.isEmpty()) {
res.add(pq.remove().e);
}
return res;
}
}
(3)用比较器来简化代码:
import java.util.*;
class Solution {
public class Freq {
int e, freq;
public Freq(int e, int freq) {
this.e = e;
this.freq = freq;
}
}
public class FreComparator implements Comparator<Freq> {//定义优先级
public int compare(Freq a, Freq b) {
return a.freq - b.freq;
}
}
public List<Integer> topKFrequent(int[] nums, int k) {
//统计频次
TreeMap<Integer, Integer> map = new TreeMap<>();
for(int num : nums) {
if(map.containsKey(num)) {
map.put(num, map.get(num) + 1);
} else {
map.put(num, 1);
}
}
//维护当前看到的前k个出现频次最高的元素
PriorityQueue<Freq> pq = new PriorityQueue<>(new FreComparator());
for(int key : map.keySet()) {
if(pq.size() < k) {
pq.add(new Freq(key, map.get(key)));
} else if(map.get(key) > pq.peek().freq) {
pq.remove();
pq.add(new Freq(key, map.get(key)));
}
}
LinkedList<Integer> res = new LinkedList<>();
while(!pq.isEmpty()) {
res.add(pq.remove().e);
}
return res;
}
}
(4)用匿名类进一步简化代码:
import java.util.*;
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
//统计频次
TreeMap<Integer, Integer> map = new TreeMap<>();
for(int num : nums) {
if(map.containsKey(num)) {
map.put(num, map.get(num) + 1);
} else {
map.put(num, 1);
}
}
//维护当前看到的前k个出现频次最高的元素
PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>() {
public int compare(Integer a, Integer b) {
return map.get(a) - map.get(b);
}
});
for(int key : map.keySet()) {
if(pq.size() < k) {
pq.add(key);
} else if(map.get(key) > map.get(pq.peek())) {
pq.remove();
pq.add(key);
}
}
LinkedList<Integer> res = new LinkedList<>();
while(!pq.isEmpty()) {
res.add(pq.remove());
}
return res;
}
}
(5)用lambda函数进一步简化代码:
import java.util.*;
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
//统计频次
TreeMap<Integer, Integer> map = new TreeMap<>();
for(int num : nums) {
if(map.containsKey(num)) {
map.put(num, map.get(num) + 1);
} else {
map.put(num, 1);
}
}
//维护当前看到的前k个出现频次最高的元素
PriorityQueue<Integer> pq = new PriorityQueue<>(
(a, b) -> map.get(a) - map.get(b)
);
for(int key : map.keySet()) {
if(pq.size() < k) {
pq.add(key);
} else if(map.get(key) > map.get(pq.peek())) {
pq.remove();
pq.add(key);
}
}
LinkedList<Integer> res = new LinkedList<>();
while(!pq.isEmpty()) {
res.add(pq.remove());
}
return res;
}
}