代码随想录栈与队列——前k个高频元素

题目

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

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2] 示例 2:

输入: nums = [1], k = 1 输出: [1] 提示:

你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。 你的算法的时间复杂度必须优于 O ( n log ⁡ n ) O(n \log n) O(nlogn)
, n 是数组的大小。 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。 你可以按任意顺序返回答案。

思路

优先级队列底层基于堆实现):在队头取元素,队尾加元素,优先队列内部自动按照元素权值排列

题目设计三块内容:

  1. 统计元素出现频率——>map
  2. 对频率排序
  3. 找出前k个高频元素——>小顶堆(因为是统计最大的前k个元素,所以用小根堆小顶堆用于降序排序

java中优先队列默认是小根堆

注意:优先队列想要实现小顶堆,要用升序定义优先队列(因为优先队列就是堆,定义小根堆就是要升序定义,才能保证根节点最小)

  • 优先队列升序定义小根堆
  • 小根堆用于降序排序

这是两个概念,不要弄混了

java代码如下:

class Solution {
    public int[] topKFrequent(int[] nums, int k) {

        int [] res = new int[k];//存最后结果

        Map<Integer,Integer> map = new HashMap<>();//key为数组元素,value为对应出现次数

        for(int num : nums){
            map.put(num, map.getOrDefault(num, 0) + 1);
        }
        
        PriorityQueue pq = new PriorityQueue<>((x,y)-> map.get(x) - map.get(y));//虽然优先队列默认是小顶堆,但是这里需要重新定义根据频率value排序,所以需要重新定义一下,根据get(key)的值value来进行升序

        for(Integer key : map.keySet()){//获取map中所有的key
            pq.add(key);//加入优先队列,只需要维持k个元素的小根堆即可
            if(pq.size() > k){//一旦超出k个
                pq.poll();//弹出堆顶元素,优先队列内部已经定义好排序规则
            }
        }

        int i = 0;
        while(!pq.isEmpty()){//将优先队列里的k个元素填入数组
            res[i++] = (int)pq.poll();
        }
        return res;
    }
}

你可能感兴趣的:(代码随想录,算法,java,数据结构)