Leetcode--Java--347. 前 K 个高频元素

题目描述

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
进阶:你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。

样例描述

示例 1:

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

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


思路

方法一:排序 + 哈希表

  1. 统计每个数出现的次数,按照出现次数大小设计一个最小堆(维护最高频的k元素)。
  2. 只要堆里元素不足k,就加入,否则和堆顶比较,若大于顶堆,则删除堆顶再加入。
  3. 注意不要惯性思维最大堆! 因为要模拟整个过程,最大堆每次弹出最大元素无法实现。

方法二:计数排序思想

  1. 开一个数组,下标作为数出现的频率,数组值记录每种数字出现次数的多少。
    Leetcode--Java--347. 前 K 个高频元素_第1张图片
  2. 第二次从后往前扫描数组,只要没凑够k次就一直移动,直到找到分界点。
  3. 再扫描数组,只要下标大于分界点的都是答案。

代码

方法一:排序 + 哈希表

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
       Map<Integer, Integer> map = new HashMap<>();
       for (int x: nums) {
           map.put(x, map.getOrDefault(x, 0) + 1);
       }
       //小根堆
       PriorityQueue<Integer> pq =  new PriorityQueue<>((a, b) -> {
           return map.get(a) - map.get(b);
       });
       //在哈希表的键中遍历,因为原数组会有键的重复
        for (Integer x: map.keySet()) {
           if (pq.size() < k) {
               pq.offer(x);
           } else if (pq.size() == k) {
               if (map.get(x) > map.get(pq.peek())) {
                   pq.poll();
                   pq.offer(x);
               }
           }
       }
       int res[] = new int[k];
       int idx = 0;
       while (!pq.isEmpty()) {
           res[idx ++ ] = pq.poll();
       }
       return res;
    }
}

方法二:计数排序思想

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        //统计每个数出现的次数
        for (int x: nums) {
            map.put(x, map.getOrDefault(x, 0) + 1);
        }
        int n = nums.length;
        //频率数组,cnt[i]表示出现次数为i的有多少个
        int cnt[] = new int[n + 1];
        //遍历出现次数的情况
        for (Integer t: map.values()) {
             cnt[t] ++;
        }
        //从后往前,寻找k高频元素分界点n
        int m = 0;
        //因为保证了答案唯一,所以一定能等于k
        while (m != k) {
            m += cnt[n];
            n --;
        }
        int res[] = new int[k];
        int idx = 0;
        //寻找出现次数大于n的就是答案
        for (Integer t: map.keySet()) {
            if (map.get(t) > n) 
            res[idx ++ ] = t;
        }
        return res;
    }
}

你可能感兴趣的:(Leetcode,计数排序思想,最小堆(topK))