秋招 - 算法

104 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第20天,点击查看活动详情 >>

一、题目描述 LeetCode - 347

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

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

示例 2:

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

二、解题思路

本题要求返回数组nums中出现频率最高的k个元素。可以考虑使用堆排序来解答,既将数组中各个元素的出现频率作为排序标准,维护一个大小为k的小顶堆,若堆中元素小于k个,则直接将当前元素加入到堆中,若堆中元素大于等于k个,则比较堆顶元素的出现频率和当前元素的出现频率,若小于当前元素的出现频率则弹出堆顶元素,并将当前元素入堆,若大于当前元素,则不改变堆。
Java中可以借助优先队列来实现小顶堆,在使用优先队列时需要定义排序规则,既重写Comparator接口的compare方法

 /**
 * @param o1 the first object to be compared.
 * @param o2 the second object to be compared.
 * @return a negative integer, zero, or a positive integer as the
 *         first argument is less than, equal to, or greater than the
 *         second.
 * @throws NullPointerException if an argument is null and this
 *         comparator does not permit null arguments
 * @throws ClassCastException if the arguments' types prevent them from
 *         being compared by this comparator.
 */
int compare(T o1, T o2);

由该方法的注释可知,该方法返回一个负数,0,正数分别表示第一个参数小于,等于,大于第二个参数,在实现小顶堆的compare方法时只需返回o1-o2即可。

三、代码

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int num : nums){
            map.put(num, map.getOrDefault(num, 0) + 1);
        }
        PriorityQueue<int[]> queue = new PriorityQueue<int[]>(new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[1] - o2[1];
            }
        });
        for (Map.Entry<Integer, Integer> entry : map.entrySet()){
            int num = entry.getKey();
            int count = entry.getValue();
            if (queue.size() == k){
                if (queue.peek()[1] < count){
                    queue.poll();
                    queue.offer(new int[]{num, count});
                }
            }else {
                queue.offer(new int[]{num, count});
            }
        }
        int[] res = new int[k];
        for (int i=0; i<k; i++){
            res[i] = queue.poll()[0];
        }
        return res;
    }
}

四、总结

本题使用小顶堆,得出了数组中出现频率最高的k个元素,时间复杂度为O(nlogk),空间复杂度为O(n)。