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) 频率有限且整数集合适用
相关推荐
沐苏瑶1 小时前
Java 搜索型数据结构全解:二叉搜索树、Map/Set 体系与哈希表
java·数据结构·算法
ccLianLian1 小时前
深度学习·DDPM
数据结构
ZoeJoy82 小时前
算法筑基(二):搜索算法——从线性查找到图搜索,精准定位数据
算法·哈希算法·图搜索算法
Alicx.2 小时前
dfs由易到难
算法·蓝桥杯·宽度优先
_日拱一卒2 小时前
LeetCode:找到字符串中的所有字母异位词
算法·leetcode
云泽8083 小时前
深入 AVL 树:原理剖析、旋转算法与性能评估
数据结构·c++·算法
Wilber的技术分享4 小时前
【LeetCode高频手撕题 2】面试中常见的手撕算法题(小红书)
笔记·算法·leetcode·面试
邪神与厨二病4 小时前
Problem L. ZZUPC
c++·数学·算法·前缀和
梯度下降中5 小时前
LoRA原理精讲
人工智能·算法·机器学习
IronMurphy5 小时前
【算法三十一】46. 全排列
算法·leetcode·职场和发展