【代码随想录13】前 K 个高频元素

题目 

给定一个非空的整数数组,返回其中出现频率前 k 高的元素。

示例 1:

  • 输入: nums = [1,1,1,2,2,3], k = 2
  • 输出: [1,2]

示例 2:

  • 输入: nums = [1], k = 1
  • 输出: [1]

提示:

  • 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
  • 你的算法的时间复杂度必须优于 $O(n \log n)$ , n 是数组的大小。
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
  • 你可以按任意顺序返回答案。

思路 

这题有两个关键要搞清的点:

  1. 如何求每个元素出现的次数?
  2. 如何得到topk个出现次数的元素?

首先得到每个元素出现的次数是多少,练习了那么久,自然而然想到用字典结构去存储每个元素及对应的出现次数, 线性扫一遍即可。

第二个是如何根据这个字典得到出现次数最多的topk个元素,我们首先可能会想到排序,但是排序有个坏处就是需要把所有元素都参与进来排序,而当k远远小于nums长度时,我们没必要对所有元素排序,只需要找到前k个元素就行了,所以排序在这里不是最优选择。有一种结构就能每次让我们取到最大值/最小值,只需要取k次元素就可以得到答案了,它就是堆!

我们只需要维护一个大小为k的堆用来保存答案,那么用大顶堆还是小顶堆呢?如果用大顶堆,当推入的元素超过k时,最大的元素就需要被删除,就得不到我们需要的答案了,所以需要用小顶堆。当推入元素会使当前堆长度超过k时,我们只需要把最小的元素推出去,这样到最后堆中剩下的肯定都是nums中topk个出现次数最大的元素了。

class Solution:def topKFrequent(self, nums: List[int], k: int) -> List[int]:h = []d = dict()# 统计每个数出现的次数for i in range(len(nums)):d[nums[i]] = d.get(nums[i], 0) + 1# 维护大小为k的小根堆for num, v in d.items():# 这里把出现次数放到第一个位置,小根堆会默认以第一个位置进行排序heapq.heappush(h, (v, num))# 如果当前堆长度超过k,则把堆顶元素推出来,从而保证当前堆内总是最大的k个元素if len(h)>k:heapq.heappop(h)res = [0]*k# 答案要求是降序,而小根堆正序输出是升序,所以小根堆应该倒序输出for i in range(k-1, -1, -1):res[i] = heapq.heappop(h)[1]return res

事实上,我们直接把所有元素都推到一个大根堆中,再取k次堆顶元素也是可以的,而且在力扣上效率是一样的。

class Solution:def topKFrequent(self, nums: List[int], k: int) -> List[int]:d = dict()# 统计每个数出现的次数for i in range(len(nums)):d[nums[i]] = d.get(nums[i], 0) + 1h = [(-1*v, num) for num, v in d.items()]heapq.heapify(h)res = [0]*kfor i in range(k):res[i] = heapq.heappop(h)[1]return res

其实还可以更暴力一点,直接库函数,效率和上面一样,不过这样就失去了训练的意义了,在掌握了前两种写法后可以玩一玩库函数。

class Solution:def topKFrequent(self, nums: List[int], k: int) -> List[int]:d = dict()# 统计每个数出现的次数for i in range(len(nums)):d[nums[i]] = d.get(nums[i], 0) + 1h = [(v, num) for num, v in d.items()]res = heapq.nlargest(k,h)return [v for num, v in res]

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

北京汽车:传统车厂向“用户服务”转型的新范本

更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群 摘要:用户决定价值 英国大文豪狄更斯曾在《双城记》中说:“这是最好的时代,也是最坏的时代”。大浪淘沙之下,汽车产业…

C#为什么不能成为大学编程入门的首选?

大学编程入门不以C#作为首选的原因有多个因素。虽然C#是一种功能强大的编程语言,但在大学编程入门阶段,通常会选择其他语言作为首选,以下是一些可能的原因: 我这里刚好有嵌入式、单片机、plc的资料需要可以私我或在评论区扣个6 …

编程小白的自学笔记九(python爬虫入门+代码详解)

系列文章目录 编程小白的自学笔记八(python中的多线程) 编程小白的自学笔记七(python中类的继承) 编程小白的自学笔记六(python中类的静态方法和动态方法) 编程小白的自学笔记五(Python类的…

【运维小知识】(一)——centos系统安装(小白入门级)

目录 1.制作系统U盘 2.安装centos系统 3.系统配置 3.1【语言】配置​编辑 3.2【软件选择】配置 3.3【安装位置】配置 3.4【主机名、root密码、网络】配置 1.制作系统U盘 首先下载软件ventoy,制作系统U盘,买个新U盘。先在笔记本电脑安装ventoy软件&a…

学员管理系统——面向对象

文章目录 前言基本思路Student.pymain.pyStudentManage.py菜单 menu()根据菜单实现程序的大概逻辑add_student() 添加学员信息delete_student() 删除学员信息modify_studnet() 修改学员信息search_student() 查找学员信息print_student() 显示所有学员信息save_student() 保存学…

寻找下一个生成式AI独角兽,亚马逊云科技创业加速器火热来袭

生成式AI让人工智能技术又一次破圈,带来了机器学习被大规模采用的历史转折点。它正在掀起新一轮的科技革命,为人类带来前所未有的颠覆性的影响,而诸多创业者也应势而上,寻求创新机遇。生成式AI可以创造全新的客户体验、提高企业内…

【文末送书】AIGC时代的数据分析与可视化

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。搜…

MySql5.6版本开启慢SQL功能-本次采用永久生效方式

文章目录 一、目的二、注意点说明三、操作步骤3.1 临时生效操作步骤3.2 永久生效操作步骤3.3 按日期生成日志文件3.4 执行成功后验证功能是否开启 四、慢SQL日志记录内容介绍五、Shell脚本 一、目的 开启 MySQL 的慢查询日志(Slow Query Log)可以帮助你…

Python爬虫学习笔记:1688商品详情API 开发API接口文档

1688API接口是阿里巴巴集团推出的一种开放平台,提供了丰富的数据接口、转换工具以及开发资源,为开发者提供了通用的应用接口及大量数据资源,支持开发者在1688上进行商品搜索、订单管理、交易报表及物流等方面的操作。 1688API接口主要包含以…

Ceph 块存储系统 RBD 接口

-创建 Ceph 块存储系统 RBD 接口- 1、创建一个名为 rbd-demo 的专门用于 RBD 的存储池 ceph osd pool create rbd-demo 64 642、将存储池转换为 RBD 模式 ceph osd pool application enable rbd-demo rbd3、初始化存储池 rbd pool init -p rbd-demo # -p 等同于 --pool4、…

harbor仓库故障排除

harbor仓库无法用docker login登录,一直报x509: cannot validate certificate for 172.17.10.29 because it doesn’t contain any IP SANs 1、检查docker和harbor的服务是否启动 [rootk8s-harbor harbor]#systemctl status harbor.service [rootk8s-harbor harbo…

换零钱II:零钱面值动态变化,class方法自动兑换最少零钱(贪心算法)

银行现存零钱面值种类动态变化但数量无限,类方法change()完成指定金额的最少零钱个数兑换。 (本笔记适合学透python基本数据结构,熟悉class的基构造,对类内全局变量有一定认的 coder 翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1…