leetcode347.前k个高频元素

https://leetcode-cn.com/problems/top-k-frequent-elements/

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        int[] res = new int[k];
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int num:nums){
            map.put(num,map.getOrDefault(num, 0) + 1);
        }
        //使用小顶堆,重写比较器,比较map.get(x)的大小,而不是直接比较x的大小。
        PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>(){
            @Override
            public int compare(Integer o1, Integer o2){
                return map.get(o1) - map.get(o2);
            }
        });
        //保持小顶堆的length为k
        for(Integer key:map.keySet()){
            if(pq.size() < k){
                pq.add(key);
            } else{ 
                pq.add(key);
                pq.remove();
            }
        }
        //把小顶堆的key全部输出到数组中就是答案
        for(int i = 0;i < res.length;i++) {
            res[i] = pq.remove();
        }
        return res;
    }
}

换种简洁的写法:

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        int[] res = new int[k];
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int num:nums){
            map.put(num,map.getOrDefault(num, 0) + 1);
        }
        //使用小顶堆,重写比较器,比较map.get(x)的大小,而不是直接比较x的大小。
        PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>(){
            @Override
            public int compare(Integer o1, Integer o2){
                return map.get(o1) - map.get(o2);
            }
        });
        //先构建小顶堆,再把多余的元素丢掉
        for(Integer key:map.keySet())pq.add(key);
        while(pq.size() > k) pq.remove();
        
        int i = 0;
        //把小顶堆的key全部输出到数组中就是答案
        while(!pq.isEmpty()) res[i++] = pq.remove();
        return res;
    }
}

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        int[] res = new int[k];
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int num:nums){
            map.put(num,map.getOrDefault(num, 0) + 1);
        }
        //使用大顶堆,重写比较器,比较map.get(x)的大小,而不是直接比较x的大小。
        PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>(){
            @Override
            public int compare(Integer o1, Integer o2){
                return map.get(o2) - map.get(o1);
            }
        });
        //先构建大顶堆
        for(Integer key:map.keySet())pq.add(key);
        int i = 0;
        //取前k个元素
        while(i < k) res[i++] = pq.remove();
        return res;
    }
}

一共三种写法,分别讲解。

首先题目要求返回前k个频率高的元素。

分三步

        1.统计频率——使用hashmap

        2.对频率排序

        3.返回前k个元素


特别需要注意的是!!!

重写比较器的时候,比较的是map.get(o1)和o2,而不是o1和o2本身,因为传入的是keySet()(为了保证唯一性)。


使用堆排序,大顶堆的话返回前k个元素,小顶堆的话,remove掉dui.size() - k个元素,只保留下面的k个元素即可。

第一种写法,构建小顶堆的时候,小于k个元素时,直接添加,当等于k时,堆顶元素跟要加入的key做比较,map.get(key)更大的留下,一直保持在k个元素的小顶堆。

第二种写法,直接构建完小顶堆,去掉多余的元素。

第三种写法,构建大顶堆,只取前k个。

第一种空间消耗得最少,小数据量下三种写法差不多。



class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        int[] result = new int[k];
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int num : nums) {
            map.put(num, map.getOrDefault(num, 0) + 1);
        }

        Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
        // 根据map的value值正序排,相当于一个小顶堆
        PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>((o1, o2) -> o1.getValue() - o2.getValue());
        for (Map.Entry<Integer, Integer> entry : entries) {
            queue.offer(entry);
            if (queue.size() > k) {
                queue.poll();
            }
        }
        for (int i = k - 1; i >= 0; i--) {
            result[i] = queue.poll().getKey();
        }
        return result;
    }
}

再放一个Carl(代码随想录)写的

https://github.com/youngyangyang04/leetcode-master/blob/master/problems/0347.%E5%89%8DK%E4%B8%AA%E9%AB%98%E9%A2%91%E5%85%83%E7%B4%A0.md

没搜过entrySet()之前,我觉得他这个写得有点绕,看不懂,搜完之后,卧槽牛逼。

entrySet一弄,小顶堆存的直接是key-value键值对,要啥有啥,可以可以!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值