【优先级队列(大顶堆 小顶堆)】【遍历哈希表键值对】Leetcode 347 前K个高频元素
【优先级队列(大顶堆 小顶堆)】【排序】Leetcode 347 前K个高频元素
- 1.不同排序法归纳
- 2.大顶堆和小顶堆
- 3.PriorityQueue操作
- 4.PriorityQueue的升序(默认)与降序
- 5.问题解决:找前K个最大的元素 :踢走最小的(堆顶的),加入比堆顶大的,最终就是最大的K个
- 6.问题解决:找前K个最小的元素 :维护一个小顶堆,最后从堆顶依次弹出K个,最终就是最小的K个
- 题目347解法
---------------🎈🎈题目链接 Leetcode 347 前K个高频元素🎈🎈-------------------
1.不同排序法归纳

2.大顶堆和小顶堆
堆是一棵完全二叉树,树中每个结点的值都不小于(或不大于)其左右孩子的值。
大顶堆和小顶堆——非常适合在数据集中进行求前k个高频或低频结果的操作。如果父亲结点是大于等于左右孩子就是大顶堆,小于等于左右孩子就是小顶堆。
| 队头 | 种类 |
|---|---|
| 最大 | 大顶堆( PriorityQueue从大到小排就是大顶堆) |
| 最小 | 小顶堆( PriorityQueue从小到大排就是小顶堆【默认】) |
3.PriorityQueue操作
- 创建优先级队列【默认创建小顶堆】:
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(); - 使用自定义比较器创建优先队列【创建大顶堆】:
PriorityQueue<Integer> customPriorityQueue = new PriorityQueue<>(Collections.reverseOrder()); - 插入元素: 如果队列已满,则抛出一个IIIegaISlabEepeplian异常
priorityQueue.add(5); - 插入元素: 添加一个元素并返回true ,如果队列已满,则返回false
priorityQueue.offer(5); - 获取队头元素:
Integer head = priorityQueue.peek(); - 弹出队头元素:
Integer removedElement = priorityQueue.poll(); - 删除指定元素
priorityQueue.remove(5); - 获取队列大小:
int size = priorityQueue.size(); - 遍历队列元素:
for (Integer element : priorityQueue) { System.out.println(element); } - 清空队列:
priorityQueue.clear();
4.PriorityQueue的升序(默认)与降序
priority_queue(优先级队列),从小到大排就是小顶堆,从大到小排就是大顶堆。
默认情况下,PriorityQueue的队列是小顶堆(即从小到大【升序】),如果需要大顶堆需要用户提供比较器
// 用户自己定义的比较器:直接实现Comparator接口,然后重写该接口中的compare方法即可
class IntCmp implements Comparator<Integer>{@Overridepublic int compare(Integer o1, Integer o2) {return o2-o1;}
}
public class TestPriorityQueue {public static void main(String[] args) {PriorityQueue<Integer> p = new PriorityQueue<>(new IntCmp()); //自定义类的优先队列需要重写比较类作为传入参数p.offer(4);p.offer(3);p.offer(2);p.offer(1);p.offer(5);System.out.println(p.peek());}
}简化写法:
PriorityQueue<int[]> my = new PriorityQueue<>((o1,o2) -> o1[1] - o2[1])
向优先级队列中传入int[]数组,排序方式根据数组的索引为[1]的元素按照升序排列
默认情况下:Java实现Comparator排序是升序,根据参数,返回值来判断是否交换
✋可参考下面的链接查看Java实现Comparator排序的方式:
🔴 Java中Comparator的升序降序使用博客
🔴 Java comparator 升序、降序、倒序从源码角度理解

5.问题解决:找前K个最大的元素 :踢走最小的(堆顶的),加入比堆顶大的,最终就是最大的K个
- 将数组中前K个元素建立一个小根堆( PriorityQueue从小到大排就是小顶堆【默认】)
- 然后用数组中剩下的元素和堆顶元素进行比较。
此时如果比堆顶元素大(说明当前堆中的K个元素一定不是最大的K个),就踢走堆顶的最小的,加入新元素,更新堆顶元素的值,最后比较完数组中剩下的元素,此时堆中就是前K个最大的元素。
6.问题解决:找前K个最小的元素 :维护一个小顶堆,最后从堆顶依次弹出K个,最终就是最小的K个
- 将数组中全部元素建立一个小根堆 (PriorityQueue从小到大排就是小顶堆【默认】)
- 弹出K个元素放进结果数组即可。
题目347解法

时间复杂度O(NlogK)
空间复杂度O(N)
1 使用hashMap存储key和value,key是元素,value是元素出现次数:
HashMap<Integer, Integer> myhashmap = new HashMap<>()
🔴for(int num:nums){myhashmap.put(num, getOrDefault(num, 0)+1);}
2 初始化优先级队列
在优先队列中存储int[ ],int[ ] 的第一个元素代表数组的值,第二个元素代表了该值出现的次数。
自定义比较器按照出现次数,从队头到队尾的顺序是从小到大排(升序),出现次数最低的在队头(相当于小顶堆)
⭐️⭐️ ⭐️可以记住(o1,o2) -> o1-o2 代表从队顶开始升序排序⭐️⭐️⭐️
⭐️⭐️ ⭐️可以记住(o1,o2) -> o1-o2 代表从队顶开始升序排序⭐️⭐️⭐️
⭐️⭐️ ⭐️可以记住(o1,o2) -> o1-o2 代表从队顶开始升序排序⭐️⭐️⭐️


🔴 PriorityQueue<int[]> pq = new PriorityQueue<>((pair1,pair2)->pair1[1]-pair2[1]);
自定义比较器:
(pair1, pair2) -> pair1[1] - pair2[1]
pair1和pair2都是整型数组int[ ],pair1[1] - pair2[1]表示比较的是两个整形数组中的第二个元素,且表示升序排序
*Comparator接口说明:
返回负数,形参中第一个参数排在前面(队头);返回正数,形参中第二个参数排在前面(队头)
⭐️⭐️ ⭐️可以记住(o1,o2) -> o1-o2 代表从队顶开始升序排序⭐️⭐️⭐️
3 使用map.entrySet() 获取key-value的set集合
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {// 循环体
}
🔴map.entrySet(): 是 Map 接口中的一个方法,它返回一个键值对Set<Map.Entry<K, V>>。map 是一个实现了 Map 接口的对象,比如 HashMap 或 TreeMap。调用 entrySet() 方法会返回一个包含 Map.Entry 对象的集合。每个 Map.Entry 对象代表了 Map 中的一个键值对。
Map.Entry接口:Map.Entry 是 Java 中的一个接口,用于表示映射(Map)中的一个键值对。在 Java 中,Map 存储的是键值对的集合,而 Map.Entry 就是这个键值对的表示。Map.Entry 接口定义了一些方法,允许你访问键和值。
Map.Entry<Integer, Integer> entry: 这是增强的 for 循环的声明部分。在每次迭代中,entry 变量会被赋值为 map.entrySet() 中的一个元素,即一个键值对。
for (Map.Entry<Integer, Integer> entry : map.entrySet()) { ... }: 这是增强的 for 循环的语法,用于遍历 map.entrySet() 返回的集合中的每个元素。在循环体中,你可以使用 entry 变量来访问键和值。
举例来说,如果 map 是一个 HashMap,它包含整数键key和整数值value的映射,那么在这个循环中,**entry.getKey()**就是当前键值对的key,**entry.getValue()** 就是当前键值对的value。这种语法的好处是,它简化了遍历 Map 的过程,使得代码更加简洁,不需要显式地使用迭代器。
具体代码实现:
【程序采用判断进行,当优先队列大小小于K的时候将键值对无脑加入,大于的时候进行判断】
(判断如果当前要添加的 myentry.getValue() 大于队列顶部元素 mypriorityqueue.peek()[1] 那就弹出队列元素,添加当前的键值对入队)
class Solution {public int[] topKFrequent(int[] nums, int k) {// 初始化hashmap:用于整理统计数据和重复的元素 key:元素 value:元素出现的次数HashMap<Integer,Integer> myhashmap = new HashMap<>();// 增强for循环 将nums中数据遍历汇总到hashmap中for(int num:nums){myhashmap.put(num, myhashmap.getOrDefault(num,0)+1);}// 首先用优先级队列维护一个小顶堆 如果新元素大于堆顶元素就弹出堆顶,加入新元素PriorityQueue<int[]> mypriorityqueue = new PriorityQueue<>((o1, o2)->o1[1]-o2[1]);// 答案数组result[]int[] result = new int[k];// 遍历hashmap的键值对for(Map.Entry<Integer,Integer> myentry : myhashmap.entrySet()){// 维护一个大小为k的小顶堆,如果优先级队列中小于K个元素,那么就无脑加入就行 等于k就需要判断了if(mypriorityqueue.size() < k){mypriorityqueue.add(new int[]{myentry.getKey(),myentry.getValue()});}// 如果超过k那就要比一下是不是比堆顶元素大,如果大那么就弹出队列元素(即为目前队列中最小的)else{ if(myentry.getValue() > mypriorityqueue.peek()[1]){mypriorityqueue.poll();mypriorityqueue.add(new int[]{myentry.getKey(),myentry.getValue()});}}}for(int i = k-1; i>=0; i--){result[i] = mypriorityqueue.poll()[0];}return result;}
}
革新1:🔴for (var x : map.entrySet()) :
在这个上下文中,var 是 Java 10 引入的局部变量类型推断的关键字。它可以在声明变量时根据赋值语句的类型自动推断变量的类型。在这里,var 被用于迭代 map.entrySet(),其中map.entrySet()返回的是一个Set<Map.Entry<K, V>>类型。
var x 实际上是推断为 Map.Entry<Integer, Integer> 类型,这使得 x.getKey() 和 x.getValue() 方法能够被正确调用
注意,使用 var 的情况下,编译器会根据上下文推断变量的实际类型,因此程序员无需手动指定类型。这在简化代码并提高可读性方面有一些好处,但有时也可能导致可读性下降,特别是在复杂的代码中。
革新2:
Queue使用时要尽量避免Collection的add()和remove()方法,add()和remove()方法在失败的时候会抛出异常。
🔴使用offer()来加入元素,使用poll()来获取并移出元素。
【程序采用先添加进优先队列,判断队列中超过k后再弹出】
class Solution {public int[] topKFrequent(int[] nums, int k) {// 初始化hashmap:用于整理统计数据和重复的元素 key:元素 value:元素出现的次数HashMap<Integer,Integer> myhashmap = new HashMap<>();// 增强for循环 将nums中数据遍历汇总到hashmap中for(int num:nums){myhashmap.put(num, myhashmap.getOrDefault(num,0)+1);}// 首先用优先级队列维护一个小顶堆 如果新元素大于堆顶元素就弹出堆顶,加入新元素PriorityQueue<int[]> mypriorityqueue = new PriorityQueue<>((o1, o2)->o1[1]-o2[1]);// 答案数组result[]int[] result = new int[k];// 遍历hashmap的键值对for(var x : myhashmap.entrySet()){// 利用var局部变量类型推断的关键字,获取map.entrySet()返回的Map.Entry<Integer,Integer>// 可用getKey() 和 getValue()方法获取key和valueint[] temp = new int[2];temp[0] = x.getKey();temp[1] = x.getValue();// 采用offer向队列中添加元素,如果队列满就会返回false,就不会和add()方法一样报错了mypriorityqueue.offer(temp);// 先添加后判断大小,如果超过k那就要就弹出队列中最小的元素if(mypriorityqueue.size()>k){mypriorityqueue.poll();}}for(int i = k-1; i>=0; i--){result[i] = mypriorityqueue.poll()[0];}return result;}
}
相关文章:
【优先级队列(大顶堆 小顶堆)】【遍历哈希表键值对】Leetcode 347 前K个高频元素
【优先级队列(大顶堆 小顶堆)】【排序】Leetcode 347 前K个高频元素 1.不同排序法归纳2.大顶堆和小顶堆3.PriorityQueue操作4.PriorityQueue的升序(默认)与降序5.问题解决:找前K个最大的元素 :踢走最小的&…...
Java设计模式-模板方法模式(14)
行为型模式 行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对…...
【C++ 二维前缀和】约会
题目描述 从前,小兔发现了一个神秘的花园。 花园是一个 n 行 m 列的矩阵,第 i 行 j 列的花的美丽度为 ai,j,一个合法的约会场所为任意一个正方形子矩阵,定义子矩阵的浪漫度为这个子矩阵的两条对角线上的花的美丽度之和。 现在小兔…...
基于Springboot的社区疫情防控平台
末尾获取源码作者介绍:大家好,我是墨韵,本人4年开发经验,专注定制项目开发 更多项目:CSDN主页YAML墨韵 学如逆水行舟,不进则退。学习如赶路,不能慢一步。 一、项目简介 以往的社区疫情防控管理…...
JAVA中的类方法
一、定义 1.类方法也叫静态方法 格式 访问修饰符 static 数据返回类型 方法名(){} 2.类方法的调用 前提:满足访问修饰符的访问权限 使用方式:类名.类方法名或者对象名.类方法名 二、注意事项 1.类方法中没有this的参数 class D{private int n1 …...
rust嵌入式开发之RTICvsEmbassy
RTIC和Embassy是目前rust嵌入式开发中比较热门的两个框架。本来呢,针对RTIC的移植已经完成了一小半,但在移植过程中感受到了RTIC的不足,正好跳出来全面考察下embassy,本文就是根据目前的尝试结果做个对比总结。 RTIC和Embassy是两…...
Bug地狱 #1 突然宕机,企业级应用到底怎么了
Bug地狱 #1 突然宕机,企业级应用到底怎么了 背景 目前就职的企业经营是一家服务小微门店Saas企业,以进销存管理和客户营销为主体提供订阅服务。项目正式上线可以说是从13年,基础架构是Web和后端使用C# .net,数据库使用SQL Serve…...
使用 Python、Elasticsearch 和 Kibana 分析波士顿凯尔特人队
作者:来自 Jessica Garson 大约一年前,我经历了一段压力很大的时期,最后参加了一场篮球比赛。 在整个过程中,我可以以一种我以前无法做到的方式断开连接并找到焦点。 我加入的第一支球队是波士顿凯尔特人队。 波士顿凯尔特人队是…...
探索C语言结构体:编程中的利器与艺术
✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C语言学习 贝蒂的主页:Betty‘s blog 1. 常量与变量 1. 什么是结构体 在C语言中本身就自带了一些数据类型&#x…...
Git介绍与常用命令总结
Git介绍与其常用命令总结 1、Git介绍2、Git的使用3、Git常用命令3.1 初始化仓库3.2 克隆仓库3.3 配置用户信息3.4 提交代码(Commit)3.5 推送代码(Push)3.6 拉取代码(Pull)3.7 分支(Branch)3.8 远程仓库(Remote)3.9 撤销回退本地改动3.10 更新本地仓库与远程仓库 1、Git介绍 Gi…...
机器学习 | 探索朴素贝叶斯算法的应用
朴素贝叶斯算法是一种基于贝叶斯定理和特征条件独立假设的分类算法。它被广泛应用于文本分类、垃圾邮件过滤、情感分析等领域,并且在实际应用中表现出色。 朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法: 1)对于给定的待分类项r…...
【无刷电机学习】电流采样电路硬件方案
【仅作自学记录,不出于任何商业目的】 目录 AD8210 INA282 INA240 INA199 AD8210 【AD8210数据手册】 在典型应用中,AD8210放大由负载电流通过分流电阻产生的小差分输入电压。AD8210抑制高共模电压(高达65V),并提供接地参考缓冲输出&…...
对于协同过滤算法我自己的一些总结和看法
文章目录 协同过滤算法的基本原理协同过滤算法的分类用户相似度计算UserCF && ItemCF应用场景 协同过滤算法的优缺点优点缺点 协同过滤算法的总结与展望Q&A 协同过滤算法的基本原理 关于协同过滤算法,我看过很多老师写的博客以及一些简单的教程&#x…...
数据库管理phpmyadmin
子任务1-PHPmyadmin软件的使用 本子任务讲解phpmyadmin的介绍和使用操作。 训练目标 1、掌握PHPmyadmin软件的使用方法。 步骤1 phpMyAdmin 介绍 phpmyadmin是一个用PHP编写的软件工具,可以通过web方式控制和操作MySQL数据库。通过phpMyAdmin可以完全对数据库进行…...
Oracle数据表ID自增操作
一、Oracle ID自增长功能介绍 Oracle数据库默认不支持像 SQLServer、MySQL中的自增长(auto increment)功能,即自动为每一行记录的自增长字段生成下一个值。 二、Oracle ID自增长方法 第一种,通过序列(sequence&#…...
npm WARN deprecated uuid@3.4.0: Please upgrade to version 7 or higher
当使用npm下载vue3-lazy时出现一下错误时的解决方案 报错:npm WARN deprecated uuid3.4.0: Please upgrade to version 7 or higher 尝试使用过一下命令更新 npm install uuidlatest -g 是安装了最新版本的uuid, 再次下载已解决问题 ***但看某些播客依…...
第2节、让电机转起来【51单片机+L298N步进电机系列教程】
↑↑↑点击上方【目录】,查看本系列全部文章 摘要:本节介绍用简单的方式,让步进电机转起来。其目的之一是对电机转动有直观的感受,二是熟悉整个开发流程。本系列教程必要的51单片机基础包括IO口操作、中断、定时器三个部分&#…...
1154: 第多少天
题目描述 定义一个包括年、月、日的结构体变量,读入年、月、日,计算该日在当年中是第几天。注意闰年问题。 输入描述 三个整数,分别表示年、月、日。保证输入是实际存在的日期,且年份在1000至3000之间(包含1000和30…...
【C语言初阶-const作用详解】const修饰变量、const修饰指针(图文详解版)
少年,做你认为对的事 目录 少年,做你认为对的事 1.const修饰变量 2.const修饰指针(重要) 代码1: 代码2: 代码3: 编辑 3.结论 1.const修饰变量 const修饰变量将变量赋予了常量属性…...
线程协作工具类【CountDownLatch倒数门闩、Semaphore信号量、CyclicBarrier循环栏栅、Condition接口】
线程协作工具类 CountDownLatch倒数门闩Semaphore信号量CyclicBarrier循环栅栏CyclicBarrier和CountDownLatch区别: Condition接口(条件对象) 转自 极客时间 线程协作工具类就是帮助程序员更容易的让线程之间进行协作,来完成某个业务功能。 CountDownLatch倒数门闩…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...
解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...
【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
