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) 频率有限且整数集合适用
相关推荐
Keven_113 分钟前
算法札记:DP中的滚动数组
算法·滚动数组
luj_17684 分钟前
随机性在算法与占卜中的共通原理
c语言·开发语言·c++·经验分享·算法
yyds_yyd_1008617 分钟前
3731. 找出缺失的元素(2026.08.04)
c++·leetcode
Chen—LSN25 分钟前
C语言——深度理解指针(5)
c语言·数据结构·算法·排序算法
佳児素花痴╮2 小时前
树的基础知识与查找排序算法
数据结构·算法
郝学胜-神的一滴3 小时前
Python 高级编程 026:内置数据结构之骈文纵论
开发语言·数据结构·python·程序人生·软件工程
程序员老舅9 小时前
啃透 I2C 驱动开发,才算入门嵌入式 Linux 内核驱动
数据结构·驱动开发·b树·内核·嵌入式·嵌入式开发·i2c
lueluelue479 小时前
LeetCode:链表
算法·leetcode·链表
橘子汽水16812 小时前
Leetcode 23,543合并K个升序链表,二叉树的直径
算法·leetcode·链表
huameinan狮子12 小时前
Adaboost算法原理与计算实例
算法