找出一个数组中的前k个高频元素

给定一个非空的整数数组,返回其中出现频率前 k 高的元素。

例如,

给定数组 [1,1,1,2,2,3] , 和 k = 2,返回 [1,2]。

注意:

你可以假设给定的 k 总是合理的,1 ≤ k ≤ 数组中不相同的元素的个数。

第一步基本都是一致的,需要统计出每个元素的出现次数 : 先遍历一遍数组,以数组的值做key存放到map中,初始value为1,当有相同的key时,把value加1,然后map中的value就是每个元素的出现次数了.
方式1:简单暴力一点 , 然后对map中的value进行一次全排序,然后输出前k个高频的元素即可.

方式2:采用最小堆优化一下 , 构建一个容量为k的最小堆 , 遍历map中的value ,堆的数量小于k时添加 , 等于k之后,用新的value与堆中的最小值进行PK, 大于堆中的最小值就添加进堆,不大于就丢弃 , 遍历完map之后,输出堆中的元素就是前k大的元素了.

方式3:采用桶排序 , 构建n+1个桶, 每个桶里放一个数组 , (为什么是数组?因为可能2出现了5次,3也出现了5次,所以5这个桶需要用数组盛放) ,然后把value对应的key填入对应的桶中 , 前k个高频元素就从桶的结束位置倒叙遍历k个元素即可. 桶排序就是典型的空间换时间.

方式4:借用了快速排序的思想,我们要找出前k个元素,构建一个从大到小的数组, 在排序的过程中,如果能找到一个基准值,前面的都比基准值大,这个基准值又是k,那么就说明,前面的数据就是前k个高频元素了.


全排序法:

 public List<Integer> topKFrequent(int[] nums, int k) {
        // 统计元素的频率
        Map<Integer, Integer> freqMap = new HashMap<>();
        for (int num : nums) {
            freqMap.put(num, freqMap.getOrDefault(num, 0) + 1);
        }
        
        // 对元素按照频率进行降序排序
        List<Map.Entry<Integer, Integer>> list = new ArrayList<>(freqMap.entrySet());
        Collections.sort(list, new Comparator<Map.Entry<Integer, Integer>>() {
            @Override
            public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
                return o2.getValue() - o1.getValue();
            }
        });
        
        // 取出前k个元素
        int count = 0;
        List<Integer> ret = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : list) {
            ret.add(entry.getKey());
            ++count;
            if (count >= k) {
                break;
            }
        }
        return ret;
    }

最小堆法:

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

        // 遍历map,用最小堆保存频率最大的k个元素
        PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer a, Integer b) {
                return map.get(a) - map.get(b);
            }
        });

        for (Integer key : map.keySet()) {
            if (pq.size() < k) {
                pq.add(key);
            } else if (map.get(key) > map.get(pq.peek())) {
                pq.remove();
                pq.add(key);
            }
        }

        // 取出最小堆中的元素
        List<Integer> ret = new ArrayList<>();
        while (!pq.isEmpty()) {
            ret.add(pq.remove());
        }

        return ret;
    }

桶排序法

 public List<Integer> topKFrequent(int[] nums, int k) {
        // 统计元素的频次
        Map<Integer, Integer> int2FreqMap = new HashMap<>(16);
        for (int num : nums) {
            int2FreqMap.put(num, int2FreqMap.getOrDefault(num, 0) + 1);
        }
        
        // 桶排序
        List<Integer>[] bucket = new List[nums.length + 1];
        for (Integer key : int2FreqMap.keySet()) {
            int freq = int2FreqMap.get(key);
            if (bucket[freq] == null) {
                bucket[freq] = new ArrayList<>();
            }
            bucket[freq].add(key);
        }
        
        // 逆序(频次由高到低)取出元素
        List<Integer> ret = new ArrayList<>();
        for (int i = nums.length; i >= 0 && ret.size() < k; --i) {
            if (bucket[i] != null) {
                for (Integer key : bucket[i]) {
                    if (ret.size()<k){
                        ret.add(key);
                    }else {
                        return ret;
                    }
                }
            }
        }
        
        return ret;
    }

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值