Given an array of integers, write a method to return the k most frequent elements.
Java Solution 1 – Heap
Time complexity is O(n*log(k)). Note that heap is often used to reduce time complexity from n*log(n) (see solution 3) to n*log(k).
public List<Integer> topKFrequent(int[] nums, int k) { //count the frequency for each element HashMap<Integer, Integer> map = new HashMap<>(); for (int num : nums) { map.put(num, map.getOrDefault(num, 0) + 1); } // create a min heap PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>(Comparator.comparing(e -> e.getValue())); //maintain a heap of size k. for (Map.Entry<Integer, Integer> entry : map.entrySet()) { queue.offer(entry); if (queue.size() > k) { queue.poll(); } } //get all elements from the heap List<Integer> result = new ArrayList<>(); while (queue.size() > 0) { result.add(queue.poll().getKey()); } //reverse the order Collections.reverse(result); return result; } |
Java Solution 2 – Bucket Sort
Time is O(n).
public List<Integer> topKFrequent(int[] nums, int k) { //count the frequency for each element HashMap<Integer, Integer> map = new HashMap<>(); for(int num: nums){ map.put(num, map.getOrDefault(num, 0) + 1); } //get the max frequency int max = 0; for(Map.Entry<Integer, Integer> entry: map.entrySet()){ max = Math.max(max, entry.getValue()); } //initialize an array of ArrayList. index is frequency, value is list of numbers ArrayList<Integer>[] arr = (ArrayList<Integer>[]) new ArrayList[max+1]; for(int i=1; i<=max; i++){ arr[i]=new ArrayList<Integer>(); } for(Map.Entry<Integer, Integer> entry: map.entrySet()){ int count = entry.getValue(); int number = entry.getKey(); arr[count].add(number); } List<Integer> result = new ArrayList<Integer>(); //add most frequent numbers to result for(int j=max; j>=1; j--){ if(arr[j].size()>0){ for(int a: arr[j]){ result.add(a); //if size==k, stop if(result.size()==k){ return result; } } } } return result; } |
obv most important how to find K top freq after mapping symbols
we can sort
we can use heap (min)
OR WE CAN use quik_select
Solution 1, you can directly store Map.Entry in PriorityQueue and you don’t need to create Pair.
PriorityQueue<Map.Entry> minHeap = new PriorityQueue(k, new comparator<Map.Entry() {//…});
Shortest Java solution with good efficiency. See my solution, I have added comments. Time is O(n).
public static int topKFrequentArray(int[] array, int k){
/* First get element and number of occurrence using HashMap */
Map hm = new HashMap();
for(int i : array){
if(hm.containsKey(i)){
hm.put(i, hm.get(i) + 1);
}
else {hm.put(i, 1);}
}
/*Since Map does not allow dups keys, let's swap the key & value and insert into multimap. This sorts it as well */
Multimap mp = ArrayListMultimap.create();
for(Map.Entry m : hm.entrySet()){
mp.put(m.getValue(),m.getKey());
}
/* Finally we extract all values (ordered by smallest) and load into a list */
List ls = new ArrayList();
Set ks = mp.keySet();
Iterator it = ks.iterator();
while (it.hasNext() ) {
ls.addAll(new ArrayList(mp.get((Integer) it.next())));
}
/* Since the biggest is last of the list, we substract k from the List Size */
return ls.get(ls.size()-k);
}
My slick java solution, easy to understand and very efficient. Time is O(n).
public static int topKFrequent(int[] array, int k){
Map hm = new HashMap();
Multimap mp = ArrayListMultimap.create();
List ls = new ArrayList();
for(int i : array){
if(hm.containsKey(i)){hm.put(i, hm.get(i) + 1); }
else {hm.put(i, 1);}
}
for(Map.Entry m : hm.entrySet()){mp.put(m.getValue(),m.getKey());}
Set ks = mp.keySet();
Iterator it = ks.iterator();
while (it.hasNext() ) {
Collection val = mp.get((Integer) it.next());
for(int i : val){ls.add(i);}
}
System.out.println("Print " +k+" Character");
for(int i=ls.size()-1, cnt=1; i>=0; cnt++, i--){if(cnt == k){return ls.get(i);}}
return 0;
}
Fixed. Thanks!
There’s a bug in solution 2-
//add most frequent numbers to result
for(int j=max; j>=1; j–){
if(arr[j].size()>0){
for(int a: arr[j]){
result.add(a);
}
}
if(result.size()==k)
break;
}
The check for result.size()==k should be inside the loop after result.add(a). This is because result.size() == k can occur when your looping each int a.
Java Solution 2 – Bucket Sort has bug.
Try this array to test:
int a[] = {1, 2, 4, 2, 2, 5, 1, 4, 2, 1, 4, 2};
int k=2;
The code below:
if (result.size() == k) {
break;
}
should be changed to:
if (result.size() >= k) {
break;
}
Treemap code can be as concise as this:
Map sortedMap = new TreeMap(new Comparator() {
public int compare(Integer o1, Integer o2) {
int diff = map.get(o2) - map.get(o1);
return diff == 0 ? 1 : diff;
}
});
sortedMap.putAll(counter);
Second solution i think the code to populate result should look like this.
for(int j=max; j>=k-1; j–){
if(count[j].size()>0){
for(int a: count[j]){
result.add(a);
}
}
}