Hot100之堆

news2025/2/4 18:11:08

我们的PriorityQueue默认为最小堆,堆顶总是为最小 

215数组中的第K个最大元素

题目

思路解析

暴力解法(不符合时间复杂度)

题目要求我们找到「数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素」。「数组排序后的第 k 个最大的元素」换句话说:从右边往左边数第 k 个元素(从 1 开始),那么从左向右数是第几个呢,我们列出几个找找规律就好了。

一共 6 个元素,找第 2 大,下标是 4;

一共 6 个元素,找第 4 大,下标是 2。

因此升序排序以后,目标元素的下标是 N−k,这里 N 是输入数组的长度

Arrays.sort(nums);
return nums[nums.length - k];

优先队列解法(堆)

我们维护一个数量为K的优先队列

我们的PriorityQueue默认为最小堆,堆顶总是为最小

所以我们一次遍历,每次数量大于K的时候踢出最小的

这样子我们遍历完后,我们就留下来了k个最大的值,第一个堆顶元素就是第K个最大的元素


最小堆的进一步优化

当我们的堆里元素为K个时,此时我们的要添加的num小于堆里面的最小值

我们可以不添加直接continue跳过

为什么一定要堆里面元素个数到k个的时候呢?

因为要是我们的数组元素总个数==K的时候

我们按那个跳过逻辑来弄,我们示例【2,1】,k=2

我们for循环会导致我们的元素【2】进去了堆,但是我们的元素【1】没进去堆,导致漏添加了元素


代码

暴力解法(不符合时间复杂度)
class Solution {
    public int findKthLargest(int[] nums, int k) {



       Arrays.sort(nums);
       return nums[nums.length - k];

       
    }

}

优先队列解法(堆)
class Solution {
    public int findKthLargest(int[] nums, int k) {

        PriorityQueue<Integer> heap=new PriorityQueue<>();
        for(int num:nums){
            heap.add(num);
            if(heap.size()>k){
                heap.poll();
            }   
        }

    return heap.peek();

       
    }

}

最小堆的进一步优化
class Solution {
    public int findKthLargest(int[] nums, int k) {

        PriorityQueue<Integer> heap=new PriorityQueue<>();
        for(int num:nums){

            if(heap.size()==k&&num<heap.peek())
            continue;

            heap.add(num);

            if(heap.size()>k){
                heap.poll();
            }   
        }

    return heap.peek();

       
    }

}

347前K个高频元素

题目

思路解析

首先我们把所有的值到放到Map结构里面

然后我们把这个Map结构map.entrySet()弄到Map结构里面

弄一个小顶堆,我们根据value来进行排序,正序,从小到大

Set<Map.Entry<Integer, Integer>> entries = map.entrySet();

// 根据map的value值正序排,相当于一个小顶堆
PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>((o1, o2) 
-> o1.getValue() - o2.getValue());

我们把EntrySet结构加入到优先队列,他会按照value大小,正序,从小到大排序

for (Map.Entry<Integer, Integer> entry : entries) {
            queue.offer(entry);
            if (queue.size() > k) {
                queue.poll();
            }
        }

遍历顺序

我们因为是小顶堆,但是我们最前面的一个是我们的频率最大的值

所以我们result【】数组要倒序加入我们的值

for (int i = k - 1; i >= 0; i--) {
            result[i] = queue.poll().getKey();
        }

代码

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        int[] result = new int[k];

        //将数组的数放到Map里
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int num : nums) {
            map.put(num, map.getOrDefault(num, 0) + 1);
        }

        Set<Map.Entry<Integer, Integer>> entries = map.entrySet();

        // 根据map的value值正序排,相当于一个小顶堆
        PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>((o1, o2) 
        -> o1.getValue() - o2.getValue());

    
        for (Map.Entry<Integer, Integer> entry : entries) {
            queue.offer(entry);
            if (queue.size() > k) {
                queue.poll();
            }
        }


        for (int i = k - 1; i >= 0; i--) {
            result[i] = queue.poll().getKey();
        }

        
        return result;
    }
}

295数据流的中位数 

题目

思路解析

left最大堆和right最小堆的意义

中位数把这 6 个数均分成了左右两部分,一边是 left=[1,2,3],另一边是 right=[4,5,6]。

我们要计算的中位数,就来自 left 中的最大值,以及 right 中的最小值

随着 addNum 不断地添加数字,我们需要:

1.保证 left 的大小和 right 的大小尽量相等。规定:在有奇数个数时,left 比 right 多 1 个数。

2.保证 left 的所有元素都小于等于 right 的所有元素。

只要时时刻刻满足以上两个要求(满足中位数的定义),我们就可以用 left 中的最大值以及 right 中的最小值计算中位数

分类讨论
如果当前 left 的大小和 right 的大小相等(并下一步往right添加元素)

如果添加的数字 num 比较大,比如添加 7,那么把 7 加到 right 中

现在 left 比 right 少 1 个数,不符合前文的规定,所以必须把 right 的最小值从 right 中去掉,添加到 left 中。如此操作后,可以保证 left 的所有元素都小于等于 right 的所有元素。

如果添加的数字 num 比较小,比如添加 0,那么把 0 加到 left 中。

这两种情况可以合并:无论 num 是大是小,都可以先把 num 加到 right 中,然后把 right 的最小值从 right 中去掉,并添加到 left 中

如果当前 left 比 right 多 1 个数(并下一步往left添加元素)

如果添加的数字 num 比较大,比如添加 7,那么把 7 加到 right 中。

如果添加的数字 num 比较小,比如添加 0,那么把 0 加到 left 中。现在 left 比 right 多 2 个数,不符合前文的规定,所以必须把 left 的最大值从 left 中去掉,添加到 right 中。如此操作后,可以保证 left 的所有元素都小于等于 right 的所有元素。

这两种情况可以合并:无论 num 是大是小,都可以先把 num 加到 left 中,然后把 left 的最大值从 left 中去掉,并添加到 right 中

总结

我们left是最大堆

我们right是最小堆

left.size()==right.size()的情况

然后我们往right添加元素,然后right是最小堆,我们让right中元素的最小值移动到left,变成left.size()>right.size()的情况

此时就是left.size()>right.size()的情况

我们往left添加元素,然后left是最大堆,我们让left中元素的最大值移动到right,这样子又变成了元素个数相等的情况

如果我们的left.size()>right.size(),因为我们的逻辑让left中的元素只能比right中最多多一个

所以此时left的最大值就是中位数

如果我们的left.size()==right.size(),我们的中位数是【(left的最大值)+(right的最小值)】/2.0

代码

class MedianFinder {
    //最大堆
    private final PriorityQueue<Integer> left=new PriorityQueue<>((a,b)->b-a);
    //最小堆
    private final PriorityQueue<Integer> right=new PriorityQueue<>();

    public MedianFinder() {

    }
    
    public void addNum(int num) {
        if(left.size()==right.size()){//两个堆内元素个数相等的情况,我们往right添加元素
        //然后弹出right的最小值加入到left里面
            right.offer(num);
            left.offer(right.poll());
        }else{//当left的元素>right的元素,我们往left添加元素
        //然后弹出left的最大值加入到right里面
            left.offer(num);
            right.offer(left.poll());
        }        
    }
    
    public double findMedian() {
        if(left.size()>right.size()){
            return left.peek();
        }

        return(left.peek()+right.peek())/2.0;

    }
}

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */

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

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

相关文章

KNIME:开源 AI 数据科学

KNIME&#xff08;Konstanz Information Miner&#xff09;是一款开源且功能强大的数据科学平台&#xff0c;由德国康斯坦茨大学的软件工程师团队开发&#xff0c;自2004年推出以来&#xff0c;广泛应用于数据分析、数据挖掘、机器学习和可视化等领域。以下是对KNIME的深度介绍…

Office / WPS 公式、Mathtype 公式输入花体字、空心字

注&#xff1a;引文主要看注意事项。 1、Office / WPS 公式中字体转换 花体字 字体选择 “Eulid Math One” 空心字 字体选择 “Eulid Math Two” 2、Mathtype 公式输入花体字、空心字 2.1 直接输入 花体字 在 mathtype 中直接输入 \mathcal{L} L \Large \mathcal{L} L…

建表注意事项(2):表约束,主键自增,序列[oracle]

没有明确写明数据库时,默认基于oracle 约束的分类 用于确保数据的完整性和一致性。约束可以分为 表级约束 和 列级约束&#xff0c;区别在于定义的位置和作用范围 复合主键约束: 主键约束中有2个或以上的字段 复合主键的列顺序会影响索引的使用&#xff0c;需谨慎设计 添加…

Ubuntu20.04 磁盘空间扩展教程

Ubuntu20.04 磁盘空间扩展教程_ubuntu20 gpart扩容-CSDN博客文章浏览阅读2w次&#xff0c;点赞38次&#xff0c;收藏119次。执行命令查看系统容量相关的数据&#xff1a;df -h当前容量为20G&#xff0c;已用18G&#xff08;96%&#xff09;&#xff0c;可用844M&#xff0c;可用…

冯诺依曼体系架构和操作系统的概念

1.冯诺依曼体系架构 计算机的硬件大部分都遵循冯诺依曼体系架构&#xff0c;其图示如下 这里的存储器指的是内存&#xff0c;是一种断电易失的设备。 速度快 而磁盘&#xff0c;是一种永久存储的设备&#xff0c;其属于外设既是输出设备又是输入设备。速度慢 而运算器是一种…

OpenGL学习笔记(六):Transformations 变换(变换矩阵、坐标系统、GLM库应用)

文章目录 向量变换使用GLM变换&#xff08;缩放、旋转、位移&#xff09;将变换矩阵传递给着色器坐标系统与MVP矩阵三维变换绘制3D立方体 & 深度测试&#xff08;Z-buffer&#xff09;练习1——更多立方体 现在我们已经知道了如何创建一个物体、着色、加入纹理。但它们都还…

Linux第105步_基于SiI9022A芯片的RGB转HDMI实验

SiI9022A是一款HDMI传输芯片&#xff0c;可以将“音视频接口”转换为HDMI或者DVI格式&#xff0c;是一个视频转换芯片。本实验基于linux的驱动程序设计。 SiI9022A支持输入视频格式有&#xff1a;xvYCC、BTA-T1004、ITU-R.656&#xff0c;内置DE发生器&#xff0c;支持SYNC格式…

测试工程师的DS使用指南

目录 引言DeepSeek在测试设计中的应用 2.1 智能用例生成2.2 边界值分析2.3 异常场景设计DeepSeek在自动化测试中的应用 3.1 脚本智能转换3.2 日志智能分析3.3 测试数据生成DeepSeek在质量保障体系中的应用 4.1 测试策略优化4.2 缺陷模式预测4.3 技术方案验证DeepSeek在测试效能…

Qt常用控件 输入类控件

文章目录 1.QLineEdit1.1 常用属性1.2 常用信号1.3 例子1&#xff0c;录入用户信息1.4 例子2&#xff0c;正则验证手机号1.5 例子3&#xff0c;验证输入的密码1.6 例子4&#xff0c;显示密码 2. QTextEdit2.1 常用属性2.2 常用信号2.3 例子1&#xff0c;获取输入框的内容2.4 例…

linux运行级别

运行级别&#xff1a;指linux系统在启动和运行过程中所处的不同的状态。 运行级别之间的切换&#xff1a;init (级别数) 示例&#xff1a; linux的运行级别一共有7种&#xff0c;分别是&#xff1a; 运行级别0&#xff1a;停机状态 运行级别1&#xff1a;单用户模式/救援模式…

数据结构课程设计(四)校园导航

4 校园导航 4.1 需求规格说明 【问题描述】 一个学校平面图&#xff0c;至少包括10个以上的场所&#xff0c;每个场所带有编号、坐标、名称、类别等信息&#xff0c;两个场所间可以有路径相通&#xff0c;路长&#xff08;耗时&#xff09;各有不同。要求读取该校园平面图&a…

嵌入式知识点总结 操作系统 专题提升(四)-上下文

针对于嵌入式软件杂乱的知识点总结起来&#xff0c;提供给读者学习复习对下述内容的强化。 目录 1.上下文有哪些?怎么理解? 2.为什么会有上下文这种概念? 3.什么情况下进行用户态到内核态的切换? 4.中断上下文代码中有哪些注意事项&#xff1f; 5.请问线程需要保存哪些…

Elasticsearch基本使用详解

文章目录 Elasticsearch基本使用详解一、引言二、环境搭建1、安装 Elasticsearch2、安装 Kibana&#xff08;可选&#xff09; 三、索引操作1、创建索引2、查看索引3、删除索引 四、数据操作1、插入数据2、查询数据&#xff08;1&#xff09;简单查询&#xff08;2&#xff09;…

xxl-job 在 Java 项目的使用 以一个代驾项目中的订单模块举例

能搜到这里的最起码一定知道 xxl-job 是用来干什么的&#xff0c;我就不多啰嗦怎么下载以及它的历史了 首先我们要知道 xxl-job 这个框架的结构&#xff0c;如下图&#xff1a; xxl-job-master&#xff1a;xxl-job-admin&#xff1a;调度中心xxl-job-core&#xff1a;公共依赖…

Alibaba开发规范_异常日志之日志规约:最佳实践与常见陷阱

文章目录 引言1. 使用SLF4J日志门面规则解释代码示例正例反例 2. 日志文件的保存时间规则解释 3. 日志文件的命名规范规则解释代码示例正例反例 4. 使用占位符进行日志拼接规则解释代码示例正例反例 5. 日志级别的开关判断规则解释代码示例正例反例 6. 避免重复打印日志规则解释…

SQLAlchemy 2.0的简单使用教程

SQLAlchemy 2.0相比1.x进行了很大的更新&#xff0c;目前网上的教程不多&#xff0c;以下以链接mysql为例介绍一下基本的使用方法 环境及依赖 Python:3.8 mysql:8.3 Flask:3.0.3 SQLAlchemy:2.0.37 PyMySQL:1.1.1使用步骤 1、创建引擎&#xff0c;链接到mysql engine crea…

OpenGL学习笔记(七):Camera 摄像机(视图变换、LookAt矩阵、Camera类的实现)

文章目录 摄像机/观察空间/视图变换LookAt矩阵移动相机&#xff08;处理键盘输入&#xff09;移动速度欧拉角移动视角&#xff08;处理鼠标输入&#xff09;缩放场景&#xff08;处理滚轮输入&#xff09;Camera类 摄像机/观察空间/视图变换 在上一节变换中&#xff0c;我们讨…

『VUE』vue-quill-editor富文本编辑器添加按钮houver提示(详细图文注释)

目录 预览效果新建一个config.js存放标题编写添加提示的方法调用添加标题方法的生命周期总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 预览效果 新建一个config.js存放标题 export const titleConfig [{ Choice: .ql-bold…

如何使用 DeepSeek 和 Dexscreener 构建免费的 AI 加密交易机器人?

我使用DeepSeek AI和Dexscreener API构建的一个简单的 AI 加密交易机器人实现了这一目标。在本文中&#xff0c;我将逐步指导您如何构建像我一样的机器人。 DeepSeek 最近发布了R1&#xff0c;这是一种先进的 AI 模型。您可以将其视为 ChatGPT 的免费开源版本&#xff0c;但增加…

微信登录模块封装

文章目录 1.资质申请2.combinations-wx-login-starter1.目录结构2.pom.xml 引入okhttp依赖3.WxLoginProperties.java 属性配置4.WxLoginUtil.java 后端通过 code 获取 access_token的工具类5.WxLoginAutoConfiguration.java 自动配置类6.spring.factories 激活自动配置类 3.com…