小顶堆实现查找前 K 个高频元素

news2024/9/27 23:27:27

在这里插入图片描述
小顶堆(Min-Heap)通常用于实现优先队列。在小顶堆中,根节点的值是最小的,因此通过从堆中移除根节点,你可以高效地获取当前优先级最高(即值最小)的元素。

优先队列的特点

  • 允许高效地插入元素和删除具有最高优先级的元素。
  • 可以是基于不同的优先级策略(最小值、最大值等)。

小顶堆的操作

  • 插入操作:O(log n),因为在最坏的情况下,可能需要从底部移动到顶部。
  • 删除操作(取出最小值):O(log n),同样需要重建堆结构。
  • 获取最小值操作:O(1),只需返回根节点。
#时间复杂度:O(nlogk)
#空间复杂度:O(n)
import heapq
class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        #要统计元素出现频率
        map_ = {} #nums[i]:对应出现的次数
        for i in range(len(nums)):
            map_[nums[i]] = map_.get(nums[i], 0) + 1
        
        #对频率排序
        #定义一个小顶堆,大小为k
        pri_que = [] #小顶堆
        
        #用固定大小为k的小顶堆,扫描所有频率的数值
        for key, freq in map_.items():
            heapq.heappush(pri_que, (freq, key))
            if len(pri_que) > k: #如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
                heapq.heappop(pri_que)
        
        #找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组
        result = [0] * k
        for i in range(k-1, -1, -1):
            result[i] = heapq.heappop(pri_que)[1]
        return result

这段代码的目的是找出一个整数数组中出现频率最高的前K个元素。以下是对代码的详细解释:

时间复杂度与空间复杂度

  • 时间复杂度:O(n log k),其中n是数组的长度,k是要找的高频元素的数量。主要的时间开销在于维护小顶堆的操作。
  • 空间复杂度:O(n),用于存储元素及其频率的字典。

代码解析

  1. 导入模块

    import heapq
    

    导入heapq模块,用于实现小顶堆。

  2. 定义类和方法

    class Solution:
        def topKFrequent(self, nums: List[int], k: int) -> List[int]:
    

    定义一个Solution类和一个名为topKFrequent的方法,接受一个整数列表nums和一个整数k

  3. 统计频率

    map_ = {}
    for i in range(len(nums)):
        map_[nums[i]] = map_.get(nums[i], 0) + 1
    

    使用字典map_来存储每个元素及其出现的次数。通过遍历nums,更新每个元素的频率。

  4. 小顶堆的初始化

    pri_que = []
    

    初始化一个空的小顶堆pri_que

  5. 维护小顶堆

    for key, freq in map_.items():
        heapq.heappush(pri_que, (freq, key))
        if len(pri_que) > k:
            heapq.heappop(pri_que)
    

    遍历频率字典,将每个元素及其频率作为元组推入小顶堆。如果堆的大小超过k,则弹出频率最低的元素,以确保堆的大小始终为k。

  6. 提取结果

    result = [0] * k
    for i in range(k-1, -1, -1):
        result[i] = heapq.heappop(pri_que)[1]
    return result
    

    创建一个大小为k的结果数组result。然后从小顶堆中依次弹出元素,填充到结果数组中。由于小顶堆是先弹出频率最低的元素,因此需要倒序填充。

总结

这段代码有效地找出了数组中出现频率最高的前K个元素,使用字典统计频率,并利用小顶堆保持高频元素的排序,最终返回结果。

在这里插入图片描述

在这个代码片段中,使用了一个固定大小为k的小顶堆来维护频率最高的k个元素。以下是具体的步骤和举例说明:

步骤解析

  1. 初始化小顶堆:

    • 使用heapq模块创建一个空的优先队列pri_que
  2. 遍历频率映射:

    • 对于每个键值对(key, freq),将其作为元组(freq, key)插入到小顶堆中。
  3. 维护堆的大小:

    • 每次插入后,检查堆的大小。如果堆的大小超过k,则使用heapq.heappop(pri_que)弹出堆顶元素(即频率最低的元素),确保堆的大小始终保持为k。

举例说明

假设有一个频率映射map_如下:

map_ = {
    'a': 3,
    'b': 1,
    'c': 2,
    'd': 4,
    'e': 5
}

并且我们设定k = 3

执行过程
  • 初始状态: pri_que = []
  1. 插入('a', 3):

    • pri_que = [(3, 'a')]
  2. 插入('b', 1):

    • pri_que = [(1, 'b'), (3, 'a')]
  3. 插入('c', 2):

    • pri_que = [(1, 'b'), (3, 'a'), (2, 'c')]
    • 经过堆调整,变为pri_que = [(1, 'b'), (3, 'a'),(2, 'c')]
  4. 插入('d', 4):

    • pri_que = [(1, 'b'), (3, 'a'),(2, 'c'), (4, 'd')]
    • 堆大小超过k,弹出堆顶(1, 'b'):
    • pri_que = [(2, 'c'),(3, 'a'), (4, 'd')]
  5. 插入('e', 5):

    • pri_que = [(2, 'c'), (3, 'a'), (4, 'd'), (5, 'e')]
    • 堆大小再次超过k,弹出堆顶(2, 'c'):
    • pri_que = [(3, 'a'), (4, 'd'), (5, 'e')]

最终结果

经过上述操作后,pri_que中保留的元素为[(3, 'a'), (4, 'd'), (5, 'e')],即频率最高的3个元素是'a''d''e'

map_ = {  
    'a': 3,  
    'b': 1,  
    'c': 2,  
    'd': 4,  
    'e': 5,
    "f":3
}
pri_que = []
for key, freq in map_.items():
    heapq.heappush(pri_que, (freq, key))
    print(pri_que)
    if len(pri_que) > 3: #如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
        heapq.heappop(pri_que)
    print(pri_que)

好的,如果我们将上述过程的输出结果用中文表述,可以如下说明:

在每次迭代后,优先队列的状态如下:

  1. 第一次迭代 (key=‘a’, freq=3):

    • 当前优先队列:[(3, 'a')]
    • 输出:
      [(3, 'a')]
      
  2. 第二次迭代 (key=‘b’, freq=1):

    • 向优先队列添加 (1, ‘b’)。
    • 当前优先队列:[(1, 'b'), (3, 'a')]
    • 输出:
      [(1, 'b'), (3, 'a')]
      
  3. 第三次迭代 (key=‘c’, freq=2):

    • 向优先队列添加 (2, ‘c’)。
    • 当前优先队列:[(1, 'b'), (2, 'c'), (3, 'a')]
    • 输出:
      [(1, 'b'), (2, 'c'), (3, 'a')]
      
  4. 第四次迭代 (key=‘d’, freq=4):

    • 向优先队列添加 (4, ‘d’)。
    • 当前优先队列:[(1, 'b'), (2, 'c'), (3, 'a'), (4, 'd')]
    • 由于队列大小超过3,弹出最小的元素。
    • 弹出后,当前优先队列:[(2, 'c'), (3, 'a'), (4, 'd')]
    • 输出:
      [(1, 'b'), (2, 'c'), (3, 'a'), (4, 'd')]
      [(2, 'c'), (3, 'a'), (4, 'd')]
      
  5. 第五次迭代 (key=‘e’, freq=5):

    • 向优先队列添加 (5, ‘e’)。
    • 当前优先队列:[(2, 'c'), (3, 'a'), (4, 'd'), (5, 'e')]
    • 弹出最小的元素。
    • 弹出后,当前优先队列:[(3, 'a'), (4, 'd'), (5, 'e')]
    • 输出:
      [(2, 'c'), (3, 'a'), (4, 'd'), (5, 'e')]
      [(3, 'a'), (4, 'd'), (5, 'e')]
      
  6. 第六次迭代 (key=‘f’, freq=3):

    • 向优先队列添加 (3, ‘f’)。
    • 当前优先队列:[(3, 'a'), (3, 'f'), (4, 'd'), (5, 'e')]
    • 弹出最小的元素。
    • 弹出后,当前优先队列:[(3, 'f'), (4, 'd'), (5, 'e')]
    • 输出:
      [(3, 'a'), (3, 'f'), (4, 'd'), (5, 'e')]
      [(3, 'f'), (4, 'd'), (5, 'e')]
      

最终输出

综上,经过每次迭代后的输出将是:

在这里插入图片描述
在第六次迭代中,优先队列的操作顺序很重要。以下是详细的解释:

  1. 在第六次迭代中,我们添加了 (3, 'f') 到队列中。
  2. 此时优先队列中的元素是:[(3, 'a'), (3, 'f'), (4, 'd'), (5, 'e')]
  3. 因为优先队列是根据频率来排序的,频率相同的情况下,排列顺序可能取决于它们的添加顺序(先进先出)。
  4. 输入 (3, 'f') 后,队列中有两个元素频率为 3'a''f'。根据优先队列的特性,'a' 早于 'f' 被添加,因此当我们进行弹出操作时, '(3, 'a') 会被弹出。

所以,在第六次迭代结束后,优先队列的状态应该是 [(3, 'f'), (4, 'd'), (5, 'e')]。弹出的是 'a',而 f 被留下了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1988627.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024年【化工自动化控制仪表】考试及化工自动化控制仪表考试内容

题库来源:安全生产模拟考试一点通公众号小程序 化工自动化控制仪表考试参考答案及化工自动化控制仪表考试试题解析是安全生产模拟考试一点通题库老师及化工自动化控制仪表操作证已考过的学员汇总,相对有效帮助化工自动化控制仪表考试内容学员顺利通过考…

Struts2框架漏洞(附漏洞修复方法)

Apache Struts 2 最初被称为 WebWork 2,它是一个简洁的、可扩展的框架,可用于创建企业级Java web应用程序。设计这个框架是为了从构建、部署、到应用程序维护方面来简化整个开发周期。 Struts 2在2007年7月23日发布的第一个Struts 2漏洞S2-001。 …

dbeaver设置字体大小

1、【窗口】-【首选项】 2、【外观】-【颜色-字体】-【Dbeaver Fonts】-【Monospace font】 双击或者右边编辑都可以打开设置

【Linux】—— 僵尸进程、孤儿进程

🌏博客主页:PH_modest的博客主页 🚩当前专栏:Linux跬步积累 💌其他专栏: 🔴 每日一题 🟡 C跬步积累 🟢 C语言跬步积累 🌈座右铭:广积粮&#xff0…

计网学习(一)——计算机网络概述

一、计算机网络概述 Internet翻译:因特网(未得到普及)>互联网互联网基本特点:连通性和资源共享计算机网络:有若干结点和连接这些节点的链路组成网络把许多计算机连接在一起,而互连网则把许多网络通过路…

数学建模--智能算法之免疫算法

目录 基本原理 应用实例 代码示例 总结 免疫算法在免疫系统研究中的应用和进展是什么? 如何量化评估免疫算法在不同优化问题中的性能和效率? 免疫算法与其他智能优化算法(如遗传算法、粒子群优化)相比有哪些独特优势和局限性…

“tcp控制协议”的理解

情景解释: 1.过程: 在用户进行网络间通信时,不管是客户端还是服务端,都会有两个缓冲区——发送缓冲区和接受缓冲区。 通过4个缓冲区进行数据交流。 用户通过write()将数据发送到他的发送缓冲区中,再传输到服务端的…

遥感类SCI推荐合集,潜力大+易投,版面有限!

关注GZH【欧亚科睿学术】,第一时间了解期刊最新动态! 🔥 🔥 🔥 🔥 遥感类SCI期刊合集 1. 农林科学类(中科院1区TOP,领域高权威) 【期刊简介】IF:4.0-5.0&am…

Linux源码阅读笔记18-插入模型及删除模块操作

基础知识 模块是一种向Linux内核添加设备驱动程序、文件系统及其他组件的有效方法,不需要编译新内核 优点 通过使用模块,内核发布者能够预先编译大量驱动程序,而不会致使内核映像的尺寸发生膨胀。内核开发者可以将实验性的代码打包到模块中&a…

达梦数据库的系统视图v$large_mem_sqls

达梦数据库的系统视图v$large_mem_sqls 达梦数据库的V$LARGE_MEM_SQLS视图提供了最近1000条使用大内存的SQL语句信息。一条SQL语句如果使用的内存值超过ini参数LARGE_MEM_THRESHOLD,就认为使用了大内存。这个视图帮助用户监控和分析哪些SQL语句在执行时占用了大量内…

【python】Python中位运算算法详细解析与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…

torch量化接口深度解读-eager模式-fx模式

一、定义 接口总结量化模式解读 二、实现 接口总结 1. PyTorch提供了三种不同的量化模式:Eager模式量化、FX图模式量化(维护)和PyTorch 2导出量化。 2. Eager Mode Quantization是一个测试版功能。用户需要进行融合,并手动指定量…

2024年AWS云服务器选择哪个区域最好?

在选择2024年AWS云服务器区域时,您需要根据您的业务需求、目标用户群体的位置、数据合规性要求、延迟需求以及成本预算等因素综合考虑。以下是九河云针对不同需求的建议: 北美区域 优势:北美区域,尤其是弗吉尼亚北部&#xff0c…

工业和信息化部明确四方面举措优化信息通信行业营商环境

根据工业和信息化部6日发布的消息,该部门已正式下发《关于创新信息通信行业管理 优化营商环境的意见》。 此意见旨在通过四项主要措施优化行业管理制度和手段,以促进信息通信行业的高质量发展。 这些措施包括:持续改进高效、开放、统一的准…

vue项目部署在子路径中前端配置

vue.config.JS router/index.js或者是man.js

Docker-数据卷指令

数据卷挂载修改内容

Java批量查询CSDN质量分

文章目录 前言代码实现pom.xml实体类工具类质量分查询 效果开源仓库 前言 在CSDN平台申请“专家博主”、“优质创作者”等称号的时候,往往会对博客的质量分有一定的要求,这时候我们需要审视以往所发表的博客,找出质量分较低的博客&#xff0…

春秋云境 | 文件上传 | CVE-2022-23880

靶标介绍 taoCMS v3.0.2 文件管理处存在任意文件上传漏洞,攻击者可执行任意代码 开启靶场 点击下面的“管理” 发现是一个登录页面 右击点检查 发现默认账号和密码,登录进去的页面如图所示 创建一句话木马 找到了文件管理功能,新建一个 sh…

正则表达式测试工具

前言 正则表达式测试工具可供您输入正则表达式和测试文本,立即查看匹配结果. 下面是离线的HTML文件,同样可以提供相同的服务. 目录 使用说明 HTML代码 正则表达式的编写经验和方法 总结 使用说明 1.先将HTML代码存储成.html为后缀的文件; 2.然后用浏览器打开这个…

企业需要了解的平滑替代FTP 的文件传输软件知识

虽然传统的FTP曾经是行业的标准,但随着技术的发展,其局限性逐渐出现,促使各行业寻求更高效、更安全的解决方案。然而,面对市场上许多替代FTP软件,测试也消耗了人力和物质资源。今天,小编将分析市场上企业寻…