347. Top K Frequent Elements

三刷。
准备面试正好有这个题,把3种方式都撸一下试试。

先是Bucket Sort。因为我们知道所有数据(frequency)的值域:最小是0,element在数组中一次都未出现;最大是数组长度,整个数组只含此element,有了值域就适合Bucket。

前面按出现频率建map,记录每个int出现了多少次,然后按照出现次数入桶int[] bucket,最后倒着遍历,只要桶不是空的就把里面元素加到解里,K个解之后返还。

Time: 建图O(n),入桶O(n),最后检查桶,也是O(n). 最后是O(n)

Space: map O(n), bucket array O(n). 最后O(n)

public class Solution {
    public List<Integer> topKFrequent(int[] nums, int k) {
        List<Integer> res = new ArrayList<>();
        if (k == 0 || nums.length == 0) return res;
        
        Map<Integer, Integer> map = new HashMap<>();
        for (int i : nums) {
            map.put(i, map.getOrDefault(i, 0) + 1);
        }
        
        List<Integer>[] bucket = new List[nums.length + 1];
        for (int i : map.keySet()) {
            int val = map.get(i);
            if (bucket[val] == null) {
                bucket[val] = new ArrayList<Integer>();
            }
            bucket[val].add(i);
        }
        
        for (int i = bucket.length - 1; i >= 0; i--) {
            if (bucket[i] != null) {
                res.addAll(bucket[i]);
                k -= bucket[i].size();
                if (k == 0) break;
            }
        }
        
        return res;
    }
}

方法二:
Max Heap:

首先还是建图,然后按照出现频率放到maxHeap里,然后取出TOP K个就行了,很直接。

Time: 建图O(n) 入pq是 O(n*lgn) TOP K个是 O(klgn) O(n + (n+k)lgn)

Space: 图O(n),PQ takes O(n)

public class Solution {
    public List<Integer> topKFrequent(int[] nums, int k) {
        List<Integer> res = new ArrayList<>();
        if (k == 0 || nums.length == 0) return res;
        
        Map<Integer, Integer> map = new HashMap<>();
        for (int i : nums) {
            map.put(i, map.getOrDefault(i, 0) + 1);
        }
        
        PriorityQueue<Integer> pq = new PriorityQueue<Integer>(new Comparator<Integer>() {
           public int compare(Integer a, Integer b) {
               return -Integer.compare(map.get(a), map.get(b));
           }
        });
        
        for (int i : map.keySet()) {
            pq.offer(i);
        }
        
        for (int i = 0; i < k ; i++) {
            res.add(pq.poll());
        }
        
        return res;
    }
}

方法三:
MinHeap

前面一样,是miniHeap,队列最前是出现频率最小的element,而且一旦队列size大于K,直接POLL顶端,因为最小的不可能是要求的元素。

Time: 图 O(n), PQ入各种数字,然后保持K的大小应该是(n-k)lgK + KlgK(最后一个似乎可以省略,直接加PQ是可以的)

O(n + (n-KlgK)

public class Solution {
    public List<Integer> topKFrequent(int[] nums, int k) {
        List<Integer> res = new ArrayList<>();
        if (k == 0 || nums.length == 0) return res;
        
        Map<Integer, Integer> map = new HashMap<>();
        for (int i : nums) {
            map.put(i, map.getOrDefault(i, 0) + 1);
        }
        
        PriorityQueue<Integer> pq = new PriorityQueue<Integer>(k, new Comparator<Integer>() {
           public int compare(Integer a, Integer b) {
               return Integer.compare(map.get(a), map.get(b));
           } 
        });
        
        for (int i : map.keySet()) {
            pq.offer(i);
            if (pq.size() > k) {
                pq.poll();
            }
        }
        
        res.addAll(pq);
        return res;
    }
}
原文地址:https://www.cnblogs.com/reboot329/p/6128334.html