「堆」对顶堆 / LeetCode 295(C++)

目录

概述

思路

算法过程

复杂度

Code


概述

LeetCode 295:

中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。

  • 例如 arr = [2,3,4] 的中位数是 3 。
  • 例如 arr = [2,3] 的中位数是 (2 + 3) / 2 = 2.5 。

实现 MedianFinder 类:

  • MedianFinder() 初始化 MedianFinder 对象。

  • void addNum(int num) 将数据流中的整数 num 添加到数据结构中。

  • double findMedian() 返回到目前为止所有元素的中位数。与实际答案相差 10-5 以内的答案将被接受。

示例 1:

输入
["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"]
[[], [1], [2], [], [3], []]
输出
[null, null, null, 1.5, null, 2.0]

堆允许我们以logn的时间复杂度查询元素最大/最小值。那如果我们要查询第k大的元素呢

随机快速选择是一个好方法。那如果我们的数据量总是动态变化呢?

有请主角:对顶堆。 


思路

对顶堆,故名思议,两个头碰头的堆。

 对顶堆可以在元素动态变化时维护第k小/大的元素。

具体地,对顶堆左侧是大根堆,右侧是小根堆,他们头碰头对顶,而对顶位置就是第k个元素。

     二叉树描述                                    堆化数组描述    |||
|                    ||||
||                 ||||||
||||            |||||||||
|||||||      ||||||||||||          i   0 1 2 .......k......................   
|大根堆||| K |||小根堆||||     nums[i]  [ > > > > >]>|<[< < < < < < < < < < ]
|||||||      ||||||||||||
||||            |||||||||
||                 ||||||
|                    |||||||
------------------------→              ----------------------------------→元素增大                                    元素增大

实现对顶堆通常采用堆化数组实现,不过好在C++已经给我们提供priority_queue优先队列实现了堆化数组的功能。

*注意*:考虑题目并未要求对元素删除,我们可以使用priority_queue,它的结构更简单,但不支持堆顶最值弹出外的其他删除操作。如果我们需要动态变更元素,应该考虑std::set(有序集合),它也支持logn级别的访问操作,同时支持logn级别的任意元素删除(set底层其实是一颗红黑树,叫做对顶红黑树更合适)。


算法过程

求出数据流的中位数,我们可以形成这样一个对顶堆:

偶数个数据时,大根堆(左侧元素)与小根堆(右侧元素)大小相同。

奇数个数据时,大根堆(左侧元素)比小根堆(右侧元素)小1个元素。

由于左侧元素小于右侧元素,我们称大根堆(左侧元素)为small,小根堆(右侧元素)为big。

加入数据num时,我们有以下判断:

大跟堆small的size等于小根堆big的size时(此前共有偶数个元素):num先进入small,small顶部会挤出最大的一个元素,加入到big中,这样就维护了small中的元素总小于big中的元素,且big的size比small的size大1。

大跟堆small的size大于小根堆big的size时(此前共有奇数个元素):num先进入big,big顶部挤出最小的一个元素,加入small中,这样就维护了big中的元素总大于smalll中的元素,且big的size等于small的size。

priority_queue<int,vector<int>,less<int>>small;
priority_queue<int,vector<int>,greater<int>>big;
void addNum(int num) {if(small.size()==big.size()){small.push(num);big.push(small.top());small.pop();}else{big.push(num);small.push(big.top());big.pop();}
}

 访问中位数可以直接以O(1)的速度进行:

double findMedian() {if(big.size()==small.size())return (big.top()+small.top())/2.0;else return big.top();
}

这是考虑中位数的情况,如果我们维护第k大/小,可以固定一侧堆大小为k,另一侧储存其余元素与其对顶。 


复杂度

时间复杂度: O(logn)

空间复杂度: O(n)

复杂度分析:

时间分析:{

考虑堆排序时间复杂度:O(nlogn)。

每次对顶堆的插入操作只插入一个元素,将n均摊至1,故为logn。(插入n个元素达到nlogn)

另外,对顶堆的查询操作时间复杂度:O(1)

}


Code

class MedianFinder {priority_queue<int,vector<int>,less<int>>small;priority_queue<int,vector<int>,greater<int>>big;
public:MedianFinder() {}void addNum(int num) {if(small.size()==big.size()){small.push(num);big.push(small.top());small.pop();}else{big.push(num);small.push(big.top());big.pop();}}double findMedian() {if(big.size()==small.size())return (big.top()+small.top())/2.0;else return big.top();}
};

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

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

相关文章

【代码随想录Day44】动态规划Part12

115.不同的子序列 题目链接/文章讲解&#xff1a;代码随想录 视频讲解&#xff1a;动态规划之子序列&#xff0c;为了编辑距离做铺垫 | LeetCode&#xff1a;115.不同的子序列_哔哩哔哩_bilibili class Solution {public int numDistinct(String s, String t) {// 将字符串s和…

Vivado - Aurora 8B/10B IP

目录 1. 简介 2. 设计调试 2.1 Physical Layer 2.2 Link Layer 2.3 Receiver 2.4 IP 接口 2.5 调试过程 2.5.1 Block Design 2.5.2 释放 gt_reset 2.5.3 观察数据 3. 实用技巧 3.1 GT 坐标与布局 3.1.1 选择器件并进行RTL分析 3.1.2 进入平面设计 3.1.3 收发器布…

什么是凸二次规划问题

我们从凸二次规划的基本概念出发&#xff0c;然后解释它与支持向量机的关系。 一、凸二次规划问题的详细介绍 凸二次规划问题是优化问题的一类&#xff0c;目标是最小化一个凸的二次函数&#xff0c;受一组线性约束的限制。凸二次规划是一类特殊的二次规划问题&#xff0c;其…

堆排序(C++实现)

参考&#xff1a; 面试官&#xff1a;请写一个堆排序_哔哩哔哩_bilibiliC实现排序算法_c从小到大排序-CSDN博客 堆的基本概念 堆排实际上是利用堆的性质来进行排序。堆可以看做一颗完全二叉树。 堆分为两类&#xff1a; 最大堆&#xff08;大顶堆&#xff09;&#xff1a;除根…

Java-IO流使用场景

Java IO 流是Java编程中非常重要的组成部分,用于处理文件读写、网络通信等数据传输任务。 1. 字节流 1.1 读取文件 import java.io.FileInputStream; import java.io.IOException;public class ReadFileExample {public static void main(String[] args) {try (FileInputSt…

Unity实现自定义图集(一)

以下内容是根据Unity 2020.1.0f1版本进行编写的   Unity自带有图集工具,包括旧版的图集(设置PackingTag),以及新版的图集(生成SpriteAtlas)。一般来说,unity自带的图集系统已经够用了,但是实际使用上还是存在一些可优化的地方,例如加载到Canvas上的资源,打图集不能…

解释器模式与栈式机器

一、解释器模式 解释器模式是一种设计模式&#xff0c;用于定义一个语言的语法结构并为其提供解释执行的功能。它最常用于解析和执行语言的表达式&#xff0c;特别是嵌入式语言或自定义语言。在这个例子中&#xff0c;它演示了如何通过解释器模式来处理简单的算术表达式&#…

PyQt 入门教程(3)基础知识 | 3.2、加载资源文件

文章目录 一、加载资源文件1、PyQt5加载资源文件2、PyQt6加载资源文件 一、加载资源文件 常见的资源文件有图像与图标&#xff0c;下面分别介绍下加载资源文件的常用方法 1、PyQt5加载资源文件 2、PyQt6加载资源文件 PyQt6版本暂时没有提供pyrcc工具&#xff0c;下面介绍下在不…

雷池社区版本SYSlog使用教程

雷池会对恶意攻击进行拦截&#xff0c;但是日志都在雷池机器上显示 如何把日志都同步到相关设备进行统一的管理和分析呢&#xff1f; 如需将雷池攻击日志实时同步到第三方服务器, 可使用雷池的 Syslog 外发 功能 启用 Syslog 外发 进入雷池 系统设置 页面, 配置 Syslog 设置…

leetcode中常用的enumerate用法和常用场景

enumerate() 的用法 enumerate() 是 Python 的一个内置函数&#xff0c;它允许你在遍历可迭代对象&#xff08;如字符串、列表、元组等&#xff09;时&#xff0c;同时获得元素的索引和元素的值。enumerate() 是在需要对迭代的数据进行索引操作时非常有用的工具。 语法&#…

北京京恋在喧嚣的都市中助你邂逅自己的爱情

北京的夜晚&#xff0c;灯火璀璨&#xff0c;车水马龙。刘凡站在他位于国贸的公寓阳台上&#xff0c;望着眼前熙熙攘攘的街道&#xff0c;心中却有一丝落寞。32岁的他&#xff0c;是一家知名互联网公司的中层管理&#xff0c;事业有成&#xff0c;收入稳定&#xff0c;甚至朋友…

anaconda(jupyter)安装教程

目录 一、下载anaconda安装包 二、安装程序 三、怎么使用 四、把jupyter界面语言修改成中文 一、下载anaconda安装包 anaconda官网&#xff1a;下载 Anaconda Distribution |蟒蛇 清华大学开源软件镜像站官网&#xff1a;清华大学开源软件镜像站 | Tsinghua Open Source M…

嵌入式linux中条件变量的具体实现

大家好,今天主要给大家分享一下,如何使用条件变量以及具体实现方法。 第一:条件变量分析 条件变量是另一种逻辑稍微复杂一点点的同步互斥机制,他必须跟互斥锁一起配合使 他的应用场景也是非常常见的,先来看一个例子: 用,小楠是一名在校学生,每个月都会从父母那里得到一笔…

考研C语言程序设计_语法相关(持续更新)

目录 一、语法题strlen转义字符内置数据类型字符串结束标志局部变量和全局变量名字冲突 局部优先switch语句中的关键字数组初始化是否正确注意define不是关键字C语言中不能用连等判断switch( )的括号里可以是什么类型?关于if关于switch关于while 二、程序阅读题有关static有关…

【openGL学习笔记】----GLFW、GLAD环境配置

glew、glad、freeglut、glfw的区别&#xff1f; glew&#xff08;The OpenGL Extension Wrangler Library&#xff09;是对底层OpenGL接口的封装&#xff0c;可以让你的代码跨平台。glad与glew作用相同&#xff0c;可以看作它的升级版。Freeglut&#xff08;OpenGL Utility To…

Torch常用函数

博主看开源遇到的torch常用函数&#xff0c;记录方便查阅 clamp()Conv1d()expand()tril()Parameter()Identity()flatten()repeat()contiguous()narrow()view() 与 reshape()expand()squeeze()和unsqueeze()transpose()permute()size()和shapemasked_fill()new_zeros() clamp() …

熟练使用Spring Boot、Spring Cloud Alibaba微服务开发框架,并深入理解其原理 学习要求

1. Spring Boot 核心理解 自动配置&#xff1a;了解 Spring Boot 的自动配置原理&#xff08;EnableAutoConfiguration&#xff09;&#xff0c;包括如何查看和定制自动配置的内容。需要能解释 Spring Boot 如何减少样板代码。Spring Boot Starter&#xff1a;熟悉各种 starte…

Synchronized锁的升级流程详解

在Java多线程编程中&#xff0c;synchronized关键字用于确保在同一时刻只有一个线程可以访问被锁定的资源&#xff0c;从而维护数据的一致性和安全性。然而&#xff0c;在多线程环境中&#xff0c;锁的频繁获取和释放会带来性能开销。为了提高性能&#xff0c;Java虚拟机&#…

计算机组成原理(笔记7高速缓冲存储器Cache,计算机组成原理的重难点全、直接、组相连)

为什么要设立高速缓冲存储器 &#xff08;Cache&#xff09;&#xff1f; Cache是介于CPU和主存之间的小容量存储器&#xff0c;存取速度比主存快。它能高速地向CPU提供指令和数据&#xff0c;加快程序的执行速度。它是为了解决CPU和主存之间速度不匹配而采用的一项重要技术。…

10月15日,每日信息差

第一、《哈利・波特与魔法石》在中国内地总票房突破 3 亿元&#xff0c;包括 2002 年首映的 5600 万&#xff0c;2020 年重映的 1.923 亿&#xff0c;以及 2024 年重映的 5170 万。 第二、全国铁路实施新货物列车运行图&#xff0c;增开城际班列至 131 列&#xff0c;多式联运…