优先级队列(leetcode347. 前 K 个高频元素)看我掰碎了,喂你嘴里!

文章介绍了如何利用优先级队列(Java中的PriorityQueue)和哈希映射解决LeetCode第347题,即找出数组中出现频率前K的元素。通过建立小顶堆,每次新元素与堆顶元素比较,根据出现次数决定是否替换,最终得到出现频率最高的K个元素。
摘要由CSDN通过智能技术生成

优先级队列(leetcode347. 前 K 个高频元素)

347. 前 K 个高频元素

优先级队列是一种特殊的队列,与普通队列不同的是,在优先级队列中每个元素都关联一个优先级,具有高优先级的元素先出队列。优先级队列通常使用堆来实现。

优先级队列中的元素可以是任意类型,但需要满足以下条件:

  1. 可以比较大小;

  2. 可以判断相等关系。

Java 中的 PriorityQueue 就是一个优先级队列,它实现了 Queue 接口,并使用了一个小根堆来存储元素。在 PriorityQueue 中,每次出队的元素都是优先级最高的元素。当添加一个新元素时,它会根据元素的优先级自动调整堆中元素的位置,保持堆的性质。

PriorityQueue 支持以下操作:

  1. add(E e) / offer(E e):将元素 e 添加到队列中;

  2. peek():获取队列中优先级最高的元素,但不删除该元素;

  3. poll():获取并删除队列中优先级最高的元素;

  4. remove(Object o):从队列中删除元素 o;

  5. size():获取队列中元素的个数。

我们可以用优先级队列实现小顶堆,让队列保持k的大小,每次想要进来的和小顶堆的堆顶元素(就是优先级队列队头)比较,比堆顶大就进队,否则比较下一个。

本题里面我们可以用map收集每个数据的出现次数,然后用优先级队列进行比较,这样相对于快速排序,会方便很多。

例如

nums = [4,1,-1,2,-1,2,3] k = 2

在我们把nums按照key为数组元素,value为出现次数装进map中后

map:

        key         value

  • 4                 1

  • 1                 1

  • -1                2

  • 2                 2

  • 3                 1

因为k=2,所以先让key为4和1进队,此时的队列

que:

        key           value

  • 4                 1

  • 1                 1

key = -1尝试进队,和队头(key = 4)比较value(其实就是比较出现次数),发现2>1,故让队头出队,让key = -1进队,此时的队列

que:

        key         value

  • 1                 1

  • -1                2

key = 2尝试进队,和队头(key = 1)比较value(其实就是比较出现次数),发现2>1,故让队头出队,让key = 2进队,此时的队列

que:

        key         value

  • -1                2

  • 2                 2

key = 3尝试进队,和队头(key = -1)比较value(其实就是比较出现次数),发现1<2,故队列不动

此时结束循环,输出队列的所有key值。

代码

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        /*Comparator接口说明:
         * 返回负数,形参中第一个参数排在前面;返回正数,形参中第二个参数排在前面
         * 对于队列:排在前面意味着往队头靠
         * 对于堆(使用PriorityQueue实现):从队头到队尾按从小到大排就是最小堆(小顶堆),
         *                                从队头到队尾按从大到小排就是最大堆(大顶堆)--->队头元素相当于堆的根节点
         * */
        PriorityQueue<int[]> que = new PriorityQueue<>((a,b)->a[1]-b[1]);//按照升序排列,最小的在队头,所以是小顶堆
        for (int num : nums) {
            map.put(num,map.getOrDefault(num,0)+1);
        }
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            if (que.size() < k) {
                que.add(new int[]{entry.getKey(),entry.getValue()});
            }else {
                if (entry.getValue() > que.peek()[1]) {
                    que.poll();
                    que.add(new int[]{entry.getKey(),entry.getValue()});
                }
            }
        }
        int[] res = new int[k];
        int num = 0;
        for (int[] ints : que) {
            res[num++] = ints[0];
        }
        return res;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值