LeetCode Hot100(55/100)——347. 前 K 个高频元素

文章目录

一、题目描述

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

你可以按任意顺序返回答案。

示例:

复制代码
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

二、题目分析与思路导图

这道题的核心在于 统计元素出现的频率 ,然后找到出现次数最多的 k 个元素。
Top K Frequent Elements
统计频率
使用HashMap
键:元素
值:出现次数
找出前K高频
排序法
小顶堆法
桶排序法


三、解法一:排序法(简单直接)

1. 原理说明

  1. 首先遍历数组,使用 HashMap 统计每个数字的出现次数。
  2. 再将 Map 中的键值对按照出现次数降序排序。
  3. 取出前 k 个元素的键即可。

2. 流程图

开始
使用HashMap统计频率
转换为List>
按value降序排序
取前k个entry的key
返回结果数组

3. 时间复杂度与空间复杂度

  • 时间复杂度:O(N log N),排序占主导。
  • 空间复杂度:O(N),用于存储频率映射。

4. Java代码实现

java 复制代码
import java.util.*;

public class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer, Integer> freqMap = new HashMap<>();
        for (int num : nums) {
            freqMap.put(num, freqMap.getOrDefault(num, 0) + 1);
        }

        List<Map.Entry<Integer, Integer>> entries = new ArrayList<>(freqMap.entrySet());
        entries.sort((a, b) -> b.getValue() - a.getValue());

        int[] res = new int[k];
        for (int i = 0; i < k; i++) {
            res[i] = entries.get(i).getKey();
        }
        return res;
    }
}

四、解法二:最小堆法(推荐做法)

1. 原理说明

利用最小堆(PriorityQueue)的性质,维持大小为 k 的堆结构:

  • 遍历所有元素的频率;
  • 当堆的大小小于 k 时将元素加入;
  • 当堆的大小等于 k 且当前元素的频率大于堆顶频率时,弹出堆顶并添加当前元素;
  • 最后堆中的元素即为出现频率前 k 的元素。

2. 时序图

提取结果 小顶堆操作 建立频率表 输入nums和k 提取结果 小顶堆操作 建立频率表 输入nums和k 遍历nums统计频率 对每个元素频率进行入堆判断 保持堆大小不超过k 输出堆中所有元素

3. 时间复杂度与空间复杂度

  • 时间复杂度:O(N log K),因为堆操作上限为 K。
  • 空间复杂度:O(N),用于哈希表和堆存储。

4. Java代码实现

java 复制代码
import java.util.*;

public class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer, Integer> freqMap = new HashMap<>();
        for (int num : nums) {
            freqMap.put(num, freqMap.getOrDefault(num, 0) + 1);
        }

        PriorityQueue<Map.Entry<Integer, Integer>> heap =
            new PriorityQueue<>(Comparator.comparingInt(Map.Entry::getValue));

        for (Map.Entry<Integer, Integer> entry : freqMap.entrySet()) {
            heap.offer(entry);
            if (heap.size() > k) {
                heap.poll();
            }
        }

        int[] res = new int[k];
        for (int i = k - 1; i >= 0; i--) {
            res[i] = heap.poll().getKey();
        }
        return res;
    }
}

五、解法三:桶排序法(最优解)

1. 原理说明

桶排序法充分利用频率的离散性:

  1. 统计频率;
  2. 构建一个桶列表,其中桶索引表示频率,桶内容存储出现该频率的数字;
  3. 从高频桶往下搜索,直到收集够 k 个元素。

2. 时间复杂度与空间复杂度

  • 时间复杂度:O(N),因为每个元素都仅遍历一次。
  • 空间复杂度:O(N),用于存储桶。

3. Java代码实现

java 复制代码
import java.util.*;

public class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer, Integer> freqMap = new HashMap<>();
        for (int num : nums) {
            freqMap.put(num, freqMap.getOrDefault(num, 0) + 1);
        }

        List<List<Integer>> buckets = new ArrayList<>();
        for (int i = 0; i <= nums.length; i++) {
            buckets.add(new ArrayList<>());
        }

        for (Map.Entry<Integer, Integer> entry : freqMap.entrySet()) {
            int freq = entry.getValue();
            buckets.get(freq).add(entry.getKey());
        }

        List<Integer> resList = new ArrayList<>();
        for (int i = buckets.size() - 1; i >= 0 && resList.size() < k; i--) {
            resList.addAll(buckets.get(i));
        }

        int[] res = new int[k];
        for (int i = 0; i < k; i++) {
            res[i] = resList.get(i);
        }
        return res;
    }
}

六、总结与对比表

解法 核心思想 时间复杂度 空间复杂度 适用场景
排序法 哈希 + 排序 O(N log N) O(N) 数据量较小
小顶堆法 哈希 + 最小堆 O(N log K) O(N) 高频前K问题通用
桶排序法 哈希 + 桶分布 O(N) O(N) 频率有限且整数集合适用
相关推荐
uesowys1 小时前
华为OD算法开发指导-二级索引-Read and Write Path Different Version
java·算法·华为od
码农三叔1 小时前
(11-4-03)完整人形机器人的设计与实现案例:盲踩障碍物
人工智能·算法·机器人·人机交互·人形机器人
Wect1 小时前
LeetCode 92. 反转链表II :题解与思路解析
前端·算法·typescript
Wect1 小时前
LeetCode 138. 随机链表的复制:两种最优解法详解
前端·算法·typescript
近津薪荼1 小时前
优选算法——前缀和(4):除了自身以外数组的乘积
算法
李派森1 小时前
AI大模型之丙午马年运势模型的构建与求解
笔记·算法
俩娃妈教编程1 小时前
洛谷选题:P1055 [NOIP 2008 普及组] ISBN 号码
c++·算法
hans汉斯2 小时前
基于联邦学习的隐私保护和抗投毒攻击方法研究
网络·人工智能·算法·yolo·数据挖掘·聚类·汉斯出版社
!停2 小时前
数据结构二叉树—链式结构(中)
java·数据结构·算法