LeetCode刷题Medium篇Top K Frequent Elements

题目

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.

十分钟尝试

没有思路,看了solution,记住下面一句话:

 k = 1 the linear-time solution is quite simple. One could keep the frequency of elements appearance in a hash map and update the maximum element at each step.

When k > 1 we need a data structure that has a fast access to the elements ordered by their frequencies. The idea here is to use the heap which is also known as priority queue.

因为需要求top k出现频率的元素,我们需要一种数据结构能够快速根据频率找到对应的那些元素,所以桶排序可以,桶用一个数组表示,索引就是出现的次数,数组的每个元素都是一个list,用来存储这个频率的元素。最后倒序遍历数组到k为止,就可以找到频率最高的k个元素了。

除了桶排序,还有堆可以用。稍微分析堆。

正确解法-桶排序

看了思路,自己写完,代码易错点

1 初始化bucket ,类型第二个还是list,size应该为nums长度加1

2.top k的限制可以通过res的size判断

class Solution {
    public List<Integer> topKFrequent(int[] nums, int k) {
        List<Integer> res=new ArrayList();
        //List<Integer>[]  bucket=new List<Integer>[nums.length];
        List<Integer>[]  bucket=new List[nums.length+1];
        //计算频率
        Map<Integer,Integer> frenqMap=new HashMap();
        for(int i=0;i<nums.length;i++){
            frenqMap.put(nums[i],frenqMap.getOrDefault(nums[i],0)+1);
        }
        //遍历频率map,放入bucket
        for(Map.Entry entry: frenqMap.entrySet()){
            int freq=(Integer)entry.getValue();
            if(bucket[freq]==null){
                bucket[freq]=new ArrayList();
            }
            bucket[freq].add((Integer)entry.getKey());
        }
        //倒序遍历bucket,找到top k,k的限制通过res的size限制
        for(int i=bucket.length-1;i>=0&&res.size()<k;i--){
            if(bucket[i]!=null&&bucket[i].size()>0){
                res.addAll(bucket[i]);
            }
        }
        return res;
        
    }
}

正确解法-堆排序

使用堆排序,思路和上面一样,无非就是数据结构不一样,为什么用堆?因为堆类似于完全二叉树,但是有堆自己的性质,比如大根堆,根顶元素最大,所以每次我们取出根顶元素,然后调整堆,再取出根顶元素,一直取出k个,这样就能拿到top k的元素。

这里用大根堆,为了便于写代码,我们利用java里面提供的优先队列,其实就是堆的数据结构实现。

稍后我们再开篇讲解一下优先队列的原理,先看代码:

class Solution {
    public List<Integer> topKFrequent(int[] nums, int k) {
        List<Integer> res=new ArrayList();
        //大根堆,按照频率生成大根堆,所以堆顶必然是当前频率最高的元素
        PriorityQueue<Map.Entry<Integer, Integer>>  heap=new PriorityQueue<>((a,b)->(b.getValue()-a.getValue()));
        //计算频率
        Map<Integer,Integer> frenqMap=new HashMap();
        for(int i=0;i<nums.length;i++){
            frenqMap.put(nums[i],frenqMap.getOrDefault(nums[i],0)+1);
        }
        //遍历频率map,放入heap
        for(Map.Entry entry: frenqMap.entrySet()){
            heap.add(entry);
        }
        //倒序遍历bucket,找到top k,k的限制通过res的size限制
        while(res.size()<k){
                res.add(heap.poll().getKey());
            }
        return res;
        
    }
}

猜你喜欢

转载自blog.csdn.net/hanruikai/article/details/85120955
今日推荐