力扣热题——前K个高频元素

在力扣的众多题目中,"前 K 个高频元素" 是一道经典且高频出现的题目,它不仅考察了对哈希表的运用,还涉及到排序、堆等数据结构的知识。今天,我们就来深入解析这道题,看看如何高效地求解。

题目分析

首先,我们来明确一下题目要求。给定一个整数数组 nums 和一个整数 k,要求返回其中出现频率前 k 高的元素。需要注意的是,你可以按任意顺序返回答案。

比如,输入 nums = 1,1,1,2,2,3,k = 2,那么输出应该是 1,2,因为 1 出现了 3 次,2 出现了 2 次,是出现频率前 2 高的元素。

这道题的核心在于如何快速统计元素的频率,并找出频率最高的前 k 个元素。

解法一:哈希表 + 排序

思路核心:

  • 用HashMap统计每个元素的出现频率(键 = 元素,值 = 出现的次数);
  • 将HashMap的键值对(Entry)转为列表,按频率降序排序
  • 取排序后列表的前k个元素,组成结果数组。
java 复制代码
import java.util.*;

public class TopKFrequent {

    public int[] topKFrequent1(int[] nums, int k) {
        // 1. 统计元素频率:key=元素,value=出现次数
        Map<Integer, Integer> map = new HashMap<>();
        for (int num : nums) {
            // 若key不存在,默认值为0,加1后存入;若存在,直接加1
            map.put(num, map.getOrDefault(num, 0) + 1);
        }

        // 2. 将HashMap的键值对转为List,便于排序
        List<Map.Entry<Integer, Integer>> entryList = new ArrayList<>(map.entrySet());
        
        // 3. 按频率降序排序(Java 8 Lambda简化比较器)
        Collections.sort(entryList, (entry1, entry2) -> {
            // 频率高的排在前面(entry2.getValue() - entry1.getValue() 表示降序)
            return entry2.getValue() - entry1.getValue();
        });

        // 4. 取前k个元素,存入结果数组
        int[] result = new int[k];
        for (int i = 0; i < k; i++) {
            result[i] = entryList.get(i).getKey();
        }

        return result;
    }

解法二:哈希表 + 堆排序

思路核心​:

  • 仍用HashMap统计频率;
  • 用PriorityQueue(Java 内置堆结构,默认小顶堆)维护大小为 k 的堆:
  • 堆中存储 "频率 - 元素" 对,优先按频率升序排列(小顶堆特性:堆顶是当前 k 个元素中频率最小的);
  • 当堆大小 <k 时,直接加入元素;当堆大小 = k 时,若当前元素频率> 堆顶频率,弹出堆顶并加入当前元素;
  • 最后从堆中提取所有元素,即为前 k 个高频元素。
java 复制代码
import java.util.*;

public class TopKFrequent {

    public int[] topKFrequent2(int[] nums, int k) {
        // 1. 统计元素频率(同解法一)
        Map<Integer, Integer> map = new HashMap<>();
        for (int num : nums) {
            map.put(num, map.getOrDefault(num, 0) + 1);
        }

        // 2. 初始化小顶堆:按频率升序排序,堆顶为频率最小的元素
        PriorityQueue<int[]> minHeap = new PriorityQueue<>((a, b) -> a[0] - b[0]);

        // 3. 遍历频率表,维护堆大小为k
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            int num = entry.getKey();
            int count = entry.getValue();
            
            if (minHeap.size() < k) {
                // 堆未满,直接加入(存入"频率-元素"数组)
                minHeap.offer(new int[]{count, num});
            } else {
                // 堆已满,比较当前频率与堆顶频率
                if (count > minHeap.peek()[0]) {
                    // 弹出堆顶(频率最小的),加入当前元素
                    minHeap.poll();
                    minHeap.offer(new int[]{count, num});
                }
            }
        }

        // 4. 从堆中提取结果(堆中元素顺序不影响,题目允许任意顺序)
        int[] result = new int[k];
        for (int i = 0; i < k; i++) {
            result[i] = minHeap.poll()[1]; // 取出数组第1位(元素)
        }

        return result;
    }
相关推荐
Chester_19993 分钟前
CSP202206C.角色授权
开发语言·数据结构·c++·蓝桥杯
晴天的雨.9929 分钟前
类和对象下(内部类,匿名对象,对象拷贝时的编译器优化)
开发语言·c++·算法
旖旎夜光28 分钟前
LeetCode 238:除自身以外数组的乘积(前缀和) —— 题解
数据结构·c++·算法·leetcode·前缀和
一条大祥脚35 分钟前
26杭电暑期第八场(后半)快读|快写|tarjan|路径DP|mex转化|扫描线|前缀和|二分图
数据结构·算法·tarjan·杭电多校·强联通分量·动态规划dp
奈斯先生Vector38 分钟前
从“能调用”到“可运营”:AI Agent 进入多模型时代后的架构升级
java·javascript·数据库·人工智能·算法·架构·aigc
2601_956121971 小时前
Bellman-ford算法
算法
叠层归一研究院1 小时前
基于区分本源的此刻存在唯一性本体论推演
人工智能·算法
luj_17681 小时前
尾椎藏今生记忆?骨盆对应不确定性
开发语言·网络·c++·经验分享·算法
深圳多奥智能一卡(码、脸)通系统1 小时前
智能梯控SDK可直接用于第三方开发对接的接口文档说明书
服务器·前端·算法