Top K 频繁元素:桶排序算法深度解析与实现要点

Top K 频繁元素:桶排序算法深度解析与实现要点

本文深入探讨了如何使用桶排序算法高效解决“top k 频繁元素”问题。文章首先概述了问题背景,随后详细阐述了通过哈希表统计元素频率,再结合桶排序将元素按频率分组的核心思路。特别强调了在构建频率桶时,遍历哈希表的键集(`keyset()`)而非原始数组(`nums`)的重要性,以确保桶中存储的元素是唯一的。最后,提供了完整的 java 解决方案代码及详细解析,并总结了关键实现要点。

引言:理解 Top K 频繁元素问题

“Top K 频繁元素”是一个常见的算法问题,要求从一个整数数组中找出出现频率最高的 K 个元素。例如,给定数组 [1,1,1,2,2,3] 和 K=2,我们期望的输出是 [1,2],因为 1 出现了 3 次,2 出现了 2 次,它们是频率最高的两个元素。解决这类问题通常需要高效地统计元素频率,并在此基础上进行排序或选择。

核心思路:频率统计与桶排序

解决“Top K 频繁元素”问题的一个高效方法是结合使用哈希表进行频率统计和桶排序(Bucket Sort)进行元素分组。

第一步:使用哈希表统计元素频率

首先,我们需要遍历输入数组 nums,统计每个元素出现的次数。哈希表(HashMap 在 Java 中)是实现这一目标的理想数据结构,它的键(Key)存储数组中的元素,值(Value)存储该元素的出现频率。

// the frequency of each element stored in map.var map = new HashMap();for(int n : nums) {    map.put(n, map.getOrDefault(n, 0) + 1);}

这段代码遍历 nums 数组,对于每个元素 n,如果它已存在于 map 中,则将其频率加 1;否则,将其添加到 map 中,并将频率初始化为 1。

第二步:构建频率桶

在统计完所有元素的频率后,我们可以创建一个“桶”数组。这个桶数组是一个 List[] 类型,其中数组的索引代表元素的频率,而该索引处存储的 List 则包含所有具有该频率的元素。例如,bucket[3] 将是一个列表,其中包含所有出现了 3 次的元素。桶数组的大小通常为 nums.length + 1,因为元素的最高频率不会超过数组的长度。

List[] bucket = new ArrayList[nums.length + 1];

关键抉择:遍历 keySet() 与遍历原始数组 nums 的区别

在将元素放入频率桶时,一个常见的疑问是:应该遍历哈希表的键集(map.keySet())还是原始数组(nums)?这正是本问题中的核心困惑点。

为什么选择 map.keySet()

正确的做法是遍历 map.keySet()。map.keySet() 返回的是哈希表中所有唯一键的集合。这意味着我们只会处理每个不同的元素一次。

简篇AI排版 简篇AI排版

AI排版工具,上传图文素材,秒出专业效果!

简篇AI排版 554 查看详情 简篇AI排版

for(int n : map.keySet()) {    int freq = map.get(n); // 获取元素 n 的频率    if(bucket[freq] == null) {        bucket[freq] = new ArrayList();    }    bucket[freq].add(n); // 将元素 n 添加到对应频率的桶中}

通过这种方式,每个唯一的元素 n 会被精确地放入它对应的频率桶中。例如,如果数字 1 出现了 3 次,它会且仅会出现在 bucket[3] 中一次。

为什么不能直接遍历 nums

如果选择遍历原始数组 nums 来填充桶,将会导致错误的结果。

// 错误示例:for(int n : nums) {    int freq = map.get(n);    if(bucket[freq] == null) {        bucket[freq] = new ArrayList();    }    bucket[freq].add(n); // 问题:同一个元素 n 会被多次添加到桶中}

考虑数组 [1,1,1,2,2,3]。当 n 是第一个 1 时,freq 为 3,1 被添加到 bucket[3]。当 n 是第二个 1 时,freq 仍为 3,1 再次被添加到 bucket[3]。当 n 是第三个 1 时,freq 仍为 3,1 第三次被添加到 bucket[3]。最终,bucket[3] 中会包含 [1, 1, 1]。

然而,我们希望的是 bucket[3] 只包含一个 1,因为 1 是一个独立的元素,其频率为 3。问题的要求是找出“Top K 频繁元素”,这些元素本身应该是独特的。如果桶中包含重复的元素,那么在后续从桶中收集结果时,for(int element : bucket[i]) 循环将会把这些重复的元素也添加到最终结果中,导致输出不正确(可能包含重复元素或超出 K 个元素)。

完整 Java 解决方案详解

结合上述思路,以下是解决“Top K 频繁元素”问题的完整 Java 解决方案:

class Solution {    public int[] topKFrequent(int[] nums, int k) {        // 1. 初始化频率桶数组。        // 数组索引代表频率,List 存储具有该频率的元素。        // 最大频率不会超过 nums.length,所以大小为 nums.length + 1。        List[] bucket = new ArrayList[nums.length + 1];        // 2. 使用 HashMap 统计每个元素的频率。        var map = new HashMap();        for(int n : nums) {            map.put(n, map.getOrDefault(n, 0) + 1);        }        // 3. 遍历 HashMap 的键集,将每个唯一的元素放入其对应频率的桶中。        for(int n : map.keySet()) {            int freq = map.get(n); // 获取元素 n 的频率            if(bucket[freq] == null) {                bucket[freq] = new ArrayList();            }            bucket[freq].add(n); // 将元素 n 添加到 bucket[freq] 列表中        }        // 4. 从高频率到低频率遍历桶,收集 Top K 频繁元素。        int[] res = new int[k];        int resIndex = 0; // 结果数组的当前填充位置        int counter = 0;  // 已收集到的频繁元素数量        // 从 bucket 数组的末尾(最高频率)开始向前遍历        for(int i = bucket.length - 1; i >= 0; i--) {            if(bucket[i] != null) { // 如果当前频率的桶不为空                for(int element : bucket[i]) { // 遍历桶中的所有元素                    res[counter++] = element; // 将元素添加到结果数组                    if(counter == k) { // 如果已收集到 K 个元素,则返回结果                        return res;                    }                }            }        }        return res; // 理论上不会执行到这里,因为题目保证 K 是有效的    }}

代码解析:

List[] bucket = new ArrayList[nums.length + 1];: 初始化一个 ArrayList 数组作为桶。数组的每个位置 i 将存储一个 ArrayList,其中包含所有频率为 i 的元素。var map = new HashMap();: 创建哈希表 map,用于存储 元素 -> 频率 的映射。for(int n : nums) map.put(n, map.getOrDefault(n, 0) + 1);: 遍历输入数组 nums,计算每个元素的频率并存储在 map 中。for(int n : map.keySet()) { … }: 这是关键步骤。 遍历 map 的键集,即所有不同的元素。对于每个元素 n,获取其频率 freq,然后将其添加到 bucket[freq] 对应的列表中。这一步确保了每个唯一的元素只被放入其对应的频率桶一次。for(int i = bucket.length – 1; i >= 0; i–) { … }: 从桶数组的最高频率(即 bucket.length – 1)开始,向低频率遍历。if(bucket[i] != null) { … }: 检查当前频率的桶是否为空。for(int element : bucket[i]) { … }: 遍历当前频率桶中的所有元素。由于我们是从高频率开始遍历,这些元素就是频率最高的。res[counter++] = element;: 将当前元素添加到结果数组 res 中。if(counter == k) { return res; }: 如果已经收集到了 K 个元素,就立即返回结果数组。

注意事项与总结

唯一性是核心: 在将元素放入频率桶时,务必确保每个不同的元素只被放入一次。这是为什么必须遍历 map.keySet() 而不是原始 nums 数组的原因。桶数组大小: 桶数组的大小应至少为 nums.length + 1,以容纳所有可能的频率值(从 0 到 nums.length)。遍历顺序: 为了找到 Top K 频繁元素,我们需要从桶数组的末尾(代表最高频率)开始向前遍历。时间复杂度:统计频率:O(N),N 是数组 nums 的长度。填充桶:O(M),M 是 nums 中不同元素的数量,M <= N。收集结果:在最坏情况下,需要遍历所有桶和桶中的所有元素,但由于我们只收集 K 个元素,这一步的复杂度通常被 O(N) 或 O(M) 包含。总时间复杂度:O(N)。空间复杂度:哈希表:O(M),M 是不同元素的数量。桶数组:O(N)。总空间复杂度:O(N)。

通过上述方法,我们能够以线性的时间复杂度高效地解决“Top K 频繁元素”问题,并且清晰地理解了在构建频率桶时处理元素唯一性的重要性。

以上就是Top K 频繁元素:桶排序算法深度解析与实现要点的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/297617.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
如何在安装mysql后测试并发连接数
上一篇 2025年11月4日 23:34:56
条码软件批量打印鼠标标签
下一篇 2025年11月4日 23:35:01

相关推荐

  • PHP递增操作符在条件语句中的应用_PHP条件判断与递增结合实践

    前置递增(++$i)先加1后返回新值,后置递增($i++)先返回原值再加1,影响条件判断结果;如$i=5时if($i++>5)不成立,因判断用的是5,之后$i变为6;循环中常见$count++控制次数,但复杂表达式如$a++&&$b++虽合法却降低可读性,应拆分以提升维护性;实…

    2026年9月22日
    100
  • Java Collections.synchronizedList方法如何保证线程安全

    synchronizedList通过同步方法保证线程安全,使用synchronized关键字对每个操作加锁,确保单个操作的原子性;但迭代或复合操作需手动同步,否则可能引发并发异常;其性能较低,适用于读多写少、并发不高的场景,高并发下推荐使用CopyOnWriteArrayList。 Java 中 C…

    2026年9月22日
    100
  • 如何在MiniToolMovieMaker中编辑AI视频?免费AI视频剪辑的教程

    如何在MiniToolMovieMaker中编辑AI视频?免费AI视频剪辑的教程如何在MiniToolMovieMaker中编辑AI视频?免费AI视频剪辑的教程如何在MiniToolMovieMaker中编辑AI视频?免费AI视频剪辑的教程如何在MiniToolMovieMaker中编辑AI视频?免费AI视频剪辑的教程

    MiniTool MovieMaker虽无AI生成功能,但可高效编辑AI生成的MP4、MOV等格式视频或图片序列。通过导入素材后,利用其剪辑、过渡、滤镜、文字、音频处理等功能,实现AI片段的精剪、色彩统一、无缝衔接与风格化输出。支持主流视频、图片及音频格式,兼容性好,适合个人创作者进行AI内容后期整…

    2026年9月22日 用户投稿
    500
  • VSCode如何调试JavaScript代码 VSCode调试功能的实战技巧

    要在vscode中调试javascript,首先需设置断点、配置launch.json文件、选择合适的调试环境并启动调试会话;2. launch.json至关重要,常见陷阱包括program路径错误、type类型不匹配、cwd设置不当、混淆launch与attach模式以及source map配置缺…

    2026年9月22日
    000
  • 华为MateView 32对决戴尔U3223QE:专业级显示器的色彩与护眼之战,为谁的眼睛买单更值?

    华为MateView 32侧重生态协同与竖屏效率,戴尔U3223QE强在高对比度面板与扩展性,选择取决于设备生态及工作需求。 华为MateView 32和戴尔U3223QE都是定位高端的专业显示器,但设计思路和侧重点有所不同。选哪款更“值”,关键看你的工作场景、设备生态和对特定功能的重视程度。它们在…

    2026年9月22日
    000
  • Linux内核13-进程切换

    进程切换,也称为任务切换、上下文切换或任务调度,本文将探讨linux内核中进程切换的实现。我们首先理解几个关键概念。 1.1 硬件上下文 每个进程都有自己的地址空间,但所有进程共享CPU寄存器。因此,在恢复进程执行前,内核必须确保挂起时的寄存器值被重新加载到CPU寄存器中。 这些需要加载到CPU寄存…

    2026年9月22日
    200
  • 如何修改MySQL的默认端口号?

    如何修改MySQL的默认端口号?如何修改MySQL的默认端口号?如何修改MySQL的默认端口号?如何修改MySQL的默认端口号?

    修改mysql默认端口号需编辑配置文件,核心步骤为:1.定位my.cnf或my.ini文件;2.在[mysqld]段落中修改或添加port参数;3.保存后重启mysql服务。更改端口主要出于避免冲突、提升安全性和适应网络策略考虑。连接时需在客户端工具或代码中指定新端口,如命令行加-p参数、编程语言连…

    2026年9月22日 用户投稿
    1200
  • 抖音短视频如何选择合适的BGM?音乐对流量影响有多大?

    抖音短视频如何选择合适的BGM?音乐对流量影响有多大?抖音短视频如何选择合适的BGM?音乐对流量影响有多大?抖音短视频如何选择合适的BGM?音乐对流量影响有多大?抖音短视频如何选择合适的BGM?音乐对流量影响有多大?

    选对bgm能显著提升抖音视频流量。bgm不仅烘托氛围,还影响算法推荐和用户停留;平台通过音乐判断视频类型与受众,节奏感强的音乐提高完播率,增强情绪共鸣促进互动;选音乐需结合内容调性、热门趋势与受众喜好,如搞笑类配明快音乐、美食类用温馨轻音乐,关注热榜与同类账号参考;常见误区包括音量过大、风格不符、盲…

    2026年9月22日 用户投稿
    100
  • 在 Linux 中如何强制停止进程?kill 和 killall 命令有什么区别?

    在日常工作中,您可能会遇到两个用于在 linux 中强制结束程序的命令:kill和killall。虽然许多 linux 用户熟悉kill命令,但使用killall命令的人相对较少。尽管这两个命令名称相似且目的相同(终止进程),但它们在使用方式和效果上有显著区别。 那么,kill和killall之间有…

    2026年9月22日
    100
  • 一加Pro系列微信收款语音怎么开启?快速设置支付播报的方法

    首先检查微信内“收款小账本”开启语音播报功能,其次确保手机系统给予微信通知权限、关闭勿扰模式、媒体音量正常,并在电池设置中避免微信后台被限制,同时更新微信至最新版本;若需个性化,可通过系统通知渠道单独设置收款通知的声音与优先级,但无法更换播报音色;使用时注意公共场合隐私保护,务必核对屏幕金额以防误报…

    2026年9月22日
    100
  • PHP匿名函数怎么用_PHP匿名函数使用场景分析

    PHP匿名函数是无名函数,可作为回调或赋值给变量,常用在数组处理、事件回调、逻辑封装等场景,支持use引入外部变量及fn短语法,结合bindTo可访问对象私有成员。 PHP匿名函数,也叫闭包函数(Closure),是一种没有名称的函数,通常作为回调使用或赋值给变量。它在实际开发中非常灵活,尤其适合用…

    2026年9月22日
    100
  • 抖音专营店怎么添加直播号?怎么把新开的抖音号添加到专营店里

    随着抖音平台社交属性不断增强,内容生态日益丰富,越来越多电商从业者开始在该平台上开展业务。其中,抖音专营店作为电商布局的重要一环,也吸引了大量商家入驻。那么,如何将直播号加入抖音专营店中,让直播成为店铺引流和销售的新工具呢?接下来的内容将为您详细介绍。 一、为什么要在抖音专营店中添加直播号 提升店铺…

    2026年9月22日
    000
  • 为什么建议手动定义Java序列化ID

    手动定义serialVersionUID可确保序列化兼容性,避免因类结构变化导致反序列化失败。Java默认生成的ID依赖类名、字段等信息,编译环境或代码微小改动均使其改变,易引发InvalidClassException。显式声明后,可在兼容性变更时主动控制ID更新,保留原ID则允许旧版本读取新对象…

    2026年9月22日
    200
  • mysql怎么使用全文索引 mysql创建全文索引的配置方法

    mysql怎么使用全文索引 mysql创建全文索引的配置方法mysql怎么使用全文索引 mysql创建全文索引的配置方法mysql怎么使用全文索引 mysql创建全文索引的配置方法mysql怎么使用全文索引 mysql创建全文索引的配置方法

    mysql使用全文索引的核心是让数据库像搜索引擎一样理解并高效检索文本内容。1. 创建全文索引:可在建表时或之后通过alter table语句为char、varchar或text字段添加fulltext索引;2. 使用match against查询:支持自然语言模式(自动过滤停用词并按相关性排序)和…

    2026年9月22日 用户投稿
    100
  • VSCode如何通过调试变量监视列表批量追踪数据变化 VSCode变量监视列表批量追踪的新颖技巧​

    VSCode如何通过调试变量监视列表批量追踪数据变化 VSCode变量监视列表批量追踪的新颖技巧​VSCode如何通过调试变量监视列表批量追踪数据变化 VSCode变量监视列表批量追踪的新颖技巧​VSCode如何通过调试变量监视列表批量追踪数据变化 VSCode变量监视列表批量追踪的新颖技巧​VSCode如何通过调试变量监视列表批量追踪数据变化 VSCode变量监视列表批量追踪的新颖技巧​

    vscode中高效批量追踪数据变化的关键是将监视列表用作表达式求值器,而非仅添加单一变量;2. 可在监视列表中添加复杂对象路径(如user.profile.address.city)、计算表达式(如(a + b) * c)、函数调用(如calculatetotal(items))或条件判断(如myv…

    2026年9月22日 用户投稿
    000
  • 在Java中如何统计List中元素出现次数

    答案是使用Map或Stream API统计List元素频次最高效。通过HashMap手动遍历统计,或用Java 8的Stream结合groupingBy和counting()实现简洁计数,Collections.frequency适用于小数据量但性能较差,推荐Stream方式兼顾性能与可读性。 在J…

    2026年9月22日
    900
  • mysql安装完如何诊断 mysql慢查询分析与优化方法

    要解决 mysql 慢查询问题,首先要开启慢查询日志,其次使用 mysqldumpslow 分析日志,再通过 explain 查看执行计划,最后根据常见优化建议改进 sql 和索引。具体步骤如下:一、修改配置文件或动态开启慢查询日志,并设置阈值和路径;二、使用 mysqldumpslow 工具分析慢…

    2026年9月22日
    100
  • PHP如何实现视频留言评论_PHP实现视频留言评论功能

    答案:通过数据库设计、前端表单、后端处理和评论展示四步实现PHP视频留言功能。1. 创建comments表存储信息;2. 构建表单提交昵称与评论;3. 用add_comment.php接收并存入数据库;4. 在页面读取并安全输出评论,防止XSS。 要实现视频留言评论功能,PHP可以结合前端页面、数据…

    2026年9月22日
    000
  • Java中如何区分逻辑错误和系统异常

    系统异常是程序运行中由JVM抛出的RuntimeException,如空指针、数组越界,会导致程序中断并打印堆栈;逻辑错误是程序语法正确但结果不符预期,如条件写反、循环次数错误,不会崩溃但行为异常。两者区别在于是否抛出异常、是否中断执行及调试方式不同,需通过防御性编程、单元测试和日志调试加以防范。 …

    2026年9月22日
    000
  • 抖音小店如何运营?普通人开店选品与推广的实用策略

    抖音小店如何运营?普通人开店选品与推广的实用策略抖音小店如何运营?普通人开店选品与推广的实用策略抖音小店如何运营?普通人开店选品与推广的实用策略抖音小店如何运营?普通人开店选品与推广的实用策略

    新手做抖音小店最现实的问题是没钱投广告和没专业团队,解决方法是抓住选品和推广两个核心环节。一、选品要找市场需求高且利润合理的商品,避开竞争激烈或太冷门的品类,结合多平台数据测试;二、前期重点用“商品卡”推广,通过短视频展示产品使用场景并挂链接引流,成本低且适合测试;三、适当尝试直播积累经验,但不依赖…

    2026年9月22日 用户投稿
    400

发表回复

登录后才能评论
关注微信