力扣刷题:前 K 个高频元素(java实现)

题目:给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

示例 1:

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

示例 2:

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

提示:

  • 1 <= nums.length <= 105
  • k 的取值范围是 [1, 数组中不相同的元素的个数]
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

进阶:你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。

相关标签:、数组哈希表分治桶排序计数快速选择排序堆(优先队列)

解析:题目要求输出频率最高的前k个,一般看到前几个就可以考虑用堆来实现。大概构思一下,可以先用map键值对来记录数组中每个元素和该元素在数组中出现的频率,然后将这些元素放到有限队列中,取出前k个。具体代码如下所示:

public int[] topKFrequent(int[] nums, int k) {
        //定义一个map集合来存储元素和对应的频率
        Map<Integer,Integer> map = new HashMap<>();
        //for循环遍历数组,统计频率
        for (int num : nums) {
            //这个方法是判断这个元素在不在map里面,在的话就用该元素,不在就用0代替
            map.put(num,map.getOrDefault(num,0)+1);
        }
        //创建一个有限队列,参数为降序排序
        PriorityQueue<int[]> priorityQueue = new PriorityQueue<>((a,b)->b[1]-a[1]);
        //对map集合进行遍历,根据频率的大小将所有元素存储到有限队列中
        for (int key : map.keySet()) {
            priorityQueue.add(new int[]{key,map.get(key)});
        }
        int[] arr = new int[k];
        for (int i = 0; i < k; i++) {
            //弹出频率最高的元素,并存到数组中
            arr[i] = priorityQueue.poll()[0];
        }
        return arr;
    }

Java优先队列简介:
JavaPriorityQueue实现了Queue接口,不允许放入null元素;其通过堆实现,具体说是通过完全二叉树(complete binary tree)实现的小顶堆(任意一个非叶子节点的权值,都不大于其左右子节点的权值),也就意味着可以通过数组来作为PriorityQueue的底层实现。

常用方法如下:
力扣刷题:前 K 个高频元素(java实现)_第1张图片

  • add(E e)offer(E e)的语义相同,都是向优先队列中插入元素,前者在插入失败时抛出异常,后则则会返回false。对于PriorityQueue这两个方法其实没什么差别。
  • element()peek()的语义完全相同,都是获取但不删除队首元素,也就是队列中权值最小的那个元素,二者唯一的区别是当方法失败时前者抛出异常,后者返回null。根据小顶堆的性质,堆顶那个元素就是全局最小的那个;由于堆用数组表示,根据下标关系,0下标处的那个元素既是堆顶元素。所以直接返回数组0下标处的那个元素即可。
  • remove(Object o)方法用于删除队列中跟o相等的某一个元素(如果有多个相等,只删除一个),该方法不是Queue接口内的方法,而是Collection接口的方法。由于删除操作会改变队列结构,所以要进行调整;又由于删除元素的位置可能是任意的,所以调整过程比其它函数稍加繁琐。

心中有梦,眼里有光。

你可能感兴趣的:(数据结构,java,leetcode,算法)