Leetcode347. Top K Frequent Elements

12 篇文章 0 订阅
3 篇文章 0 订阅

思路一

Hashmap + Minheap

维护一个最小堆,堆顶元素的频率是整个堆中最的。

  1. 如果堆未满的话,直接往堆中添加元素
  2. 如果对已满,那就把要添加的元素的频率与堆中频率最小的元素进行比较,如果要比较的元素频率大于堆顶,则添加,否则不添加
  3. 按照条件二,遍历map中所有的Entry后
  4. 遍历完整个频率map后,最小堆中则维护着频率最大的k个entry
  5. 遍历优先级队列,然后取出优先级队列中Entry 中的getKey()即可

hashmap统计频率,minheap从中选择k个最大的元素元素,

代码(java)

class Solution {
    public List<Integer> topKFrequent(int[] nums, int k) {
    Map<Integer,Integer> map = new HashMap<>();
        //统计频率的写法,
        for(int n:nums){
            map.put(n,map.getOrDefault(n,0) + 1);
        }

        Queue<Map.Entry<Integer,Integer>> minheap = new PriorityQueue<>(k,(a,b)->(a.getValue()-b.getValue()));
        //k为堆的容量大小,
        for(Map.Entry<Integer,Integer> entry: map.entrySet()){
            
        
            //逐渐构建堆的过程,如果堆中的元素比较少于k个,直接添加
            if(minheap.size()<k)
                  minheap.add(entry);
            else{
                  Map.Entry<Integer,Integer> min = minheap.peek();
                 if(entry.getValue()>min.getValue())
                {
                    minheap.poll();
                    minheap.add(entry);
                }
            }
        }
        List<Integer> res =new ArrayList<>();
        while(!minheap.isEmpty()){
            Map.Entry<Integer,Integer> entry = minheap.poll();
            res.add(entry.getKey());
        }
        return res;
        }
        
}

最大堆 HashMap + 最大堆

改进上述代码, 直接改成最大堆即可,遍历一边HashMap中堆元素,最后即可为何最大的top k的数,
使用 LinkedList 保存结果,然后链表尾部插入或者去链表头部插入,就可以采用加入该模块的情况

// use maxHeap. Put entry into maxHeap so we can always poll a number with largest frequency
public class Solution {
    public List<Integer> topKFrequent(int[] nums, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        for(int n: nums){
            map.put(n, map.getOrDefault(n,0)+1);
        }
           
        PriorityQueue<Map.Entry<Integer, Integer>> maxHeap = 
                         new PriorityQueue<>((a,b)->(b.getValue()-a.getValue()));
        for(Map.Entry<Integer,Integer> entry: map.entrySet()){
            maxHeap.add(entry);
        }
        
        List<Integer> res = new ArrayList<>();
        while(res.size()<k){
            Map.Entry<Integer, Integer> entry = maxHeap.poll();
            res.add(entry.getKey());
        }
        return res;
    }
}


c++

typedef pair<int, int> P;
class Solution {
public:
	vector<int> topKFrequent(vector<int>& nums, int k) {
		unordered_map<int, int> cnt;
		for (int x : nums) 	cnt[x] ++;
		priority_queue<P, vector<P>, greater<P> > q;
		for (auto &x : cnt) {
			if (q.size() < k)
				q.push(make_pair(x.second, x.first));
			else {
				if (q.top().first < x.second) {
					q.pop();
					q.push(make_pair(x.second, x.first));
				}
			}
		}
		vector<int> ans;
		while (!q.empty()) {
			ans.push_back(q.top().second);
			q.pop();
		}
		return ans;
	}
};

时间复杂度

O(nlogk) ,空间复杂度为O(n)

降低时间复杂度的类型情况

Your algorithm’s time complexity must be better than O(n log n), where n is the array’s size.
** 题目条件**

利用桶排序算法的情况
如何构造桶

List [] bucket =new List[大小], 每一个都要创建开始
bucket[i] = new ArrayList<>()

HashMap + Bucket

HashMap 解决频率问题,然后每一个桶保持频率相同元素,然后添加即可,然后从最高频率开始填
这样我们从桶的后面向前面遍历,最先得到的就是出现次数最多的数字,我们找到k个后返回即可,参见代码如下

class Solution {
    public List<Integer> topKFrequent(int[] nums, int k) {
        List<Integer> res = new ArrayList<>();
        if (nums == null || nums.length < k) return res;
        Map<Integer, Integer> map = new HashMap<>();
        for (int num: nums) {
            map.put(num, map.getOrDefault(num, 0)+1);
        }
        List[] buckets = new ArrayList[nums.length+1];
        for (Map.Entry<Integer, Integer> entry: map.entrySet()) {
            int value = entry.getValue();
            if (buckets[value] == null) buckets[value] = new ArrayList<>();
            buckets[value].add(entry.getKey());
        }
        for (int i = buckets.length-1; i >= 0 && res.size() < k; i--) {
            if (buckets[i] != null) res.addAll(buckets[i]);
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值