力扣hot100:295. 数据流的中位数(两个优先队列维护中位数)

2024-06-08 03:12

本文主要是介绍力扣hot100:295. 数据流的中位数(两个优先队列维护中位数),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

LeetCode:295. 数据流的中位数
在这里插入图片描述
这个题目最快的解法应该是维护中位数,每插入一个数都能快速得到一个中位数。
根据数据范围,我们应当实现一个 O ( n l o g n ) O(nlogn) O(nlogn)的算法。

1、超时—插入排序

使用数组存储,维持数组有序,当插入一个元素时使用插入排序维持数组有序,这种方式无异于使用插入排序,时间复杂度不达标。

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2),由于每一个数都会被插入一次,插入一次的时间为 O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)
    在这里插入图片描述
class MedianFinder {
public:MedianFinder() {}void addNum(int num) {nums.emplace_back(num);for(int i = nums.size() - 1; i >= 1; -- i){if(nums[i] >= nums[i - 1]) break;swap(nums[i], nums[i-1]);}}double findMedian() {int mid = nums.size() / 2;if(nums.size() % 2 == 1)return 1.0 * nums[mid];return 1.0 * (nums[mid] + nums[mid - 1]) / 2;}
private:vector<int> nums;
};

2、中位数为根的BST

如果我们使用二分查找,找到新加入元素的位置,是否可行呢?答案是可行的,但是使用数组存储并不能很快更新。

  • 使用高效率的树形二分查找,查找和插入效率很高,可以使用AVL、红黑树、B树等
  • 但这里要求的是能快速取得中位数,普通的树形二分查找就不行了,不能通过下标快速找到。因此只能使用数组二分查找,但是插入效率又不高

根据上面的讨论,我们发现,如果能每次插入维护的一个二叉搜索树是一个完全二叉树,根附近就是中位数,并且插入操作只需要 O ( l o g n ) O(logn) O(logn)的时间,那就太好了。

这样我们就可以思考,能不能实现这样的数据结构:

  • 对于任何一段区间,满足根是中位数,且左子树小于根,根小于右子树的一个二叉搜索树
    • 我们规定偶数情况下,两个数小者作为根。如下图:
      在这里插入图片描述

如果能实现这样的数据结构,就刚好和题目要求实现“数据结构”这一说法匹配了!
(我感觉是能实现的,但是时间问题,我就先不写了,有兴趣的同学可以自行研究)

3、优先队列

维护两个优先队列,一个存储比中位数小于的最大堆,一个存储比中位数大的最小堆(包括等于的,即最小堆里面的元素可能会比最大堆多一个)。那么我们就将数分为了两堆,很显然中位数能通过某种方式从两个优先队列队头取到。

并且很显然,维护这两个堆也很容易,当需要插入一个数时,我们只需要比较两个堆队头就可以选择插入的堆。并且为了维持两个堆队头是中位数

  • 当元素数为偶数时,插入一个元素,如果插入到左边,则最后中位数会出现在左边,我们将其放入右边。如果插入到右边则直接结束
  • 当元素数为奇数,插入一个元素,如果插入到左边则结束,如果插入到右边则右边多一个需要放一个放到左边。
  • 不管怎么放,根据优先队列的性质,队头都是最值,即根据中位数将区间分为两段,通过优先队列快速进行维护,左右的边界值。

时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn),一次插入时间复杂度 O ( l o g n ) O(logn) O(logn)
空间复杂度: O ( n ) O(n) O(n)

class MedianFinder {
public:MedianFinder() {left.push(-0x3f3f3f3f);right.push(0x3f3f3f3f);}void addNum(int num) {++n;//先插入if(num >= right.top()){right.push(num);}else left.push(num);//再移动if(left.size() > right.size()){right.push(left.top());left.pop();}else{if(right.size() == left.size() + 2){left.push(right.top());right.pop();}}return;}double findMedian() {if(n & 1){//n & 1 == 1 即奇数return right.top();}return (left.top() + right.top()) / 2.0;}
private:priority_queue<int, vector<int>, less<int>> left;//左区间priority_queue<int, vector<int>, greater<int>> right;//右区间int n = 0;
};

这篇关于力扣hot100:295. 数据流的中位数(两个优先队列维护中位数)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1041065

相关文章

Spring Boot整合消息队列RabbitMQ的实现示例

《SpringBoot整合消息队列RabbitMQ的实现示例》本文主要介绍了SpringBoot整合消息队列RabbitMQ的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的... 目录RabbitMQ 简介与安装1. RabbitMQ 简介2. RabbitMQ 安装Spring

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何计算两个不同类型列表的相似度

《Python如何计算两个不同类型列表的相似度》在编程中,经常需要比较两个列表的相似度,尤其是当这两个列表包含不同类型的元素时,下面小编就来讲讲如何使用Python计算两个不同类型列表的相似度吧... 目录摘要引言数字类型相似度欧几里得距离曼哈顿距离字符串类型相似度Levenshtein距离Jaccard相

使用Navicat工具比对两个数据库所有表结构的差异案例详解

《使用Navicat工具比对两个数据库所有表结构的差异案例详解》:本文主要介绍如何使用Navicat工具对比两个数据库test_old和test_new,并生成相应的DDLSQL语句,以便将te... 目录概要案例一、如图两个数据库test_old和test_new进行比较:二、开始比较总结概要公司存在多

C#比较两个List集合内容是否相同的几种方法

《C#比较两个List集合内容是否相同的几种方法》本文详细介绍了在C#中比较两个List集合内容是否相同的方法,包括非自定义类和自定义类的元素比较,对于非自定义类,可以使用SequenceEqual、... 目录 一、非自定义类的元素比较1. 使用 SequenceEqual 方法(顺序和内容都相等)2.

解读Redis秒杀优化方案(阻塞队列+基于Stream流的消息队列)

《解读Redis秒杀优化方案(阻塞队列+基于Stream流的消息队列)》该文章介绍了使用Redis的阻塞队列和Stream流的消息队列来优化秒杀系统的方案,通过将秒杀流程拆分为两条流水线,使用Redi... 目录Redis秒杀优化方案(阻塞队列+Stream流的消息队列)什么是消息队列?消费者组的工作方式每

Redis延迟队列的实现示例

《Redis延迟队列的实现示例》Redis延迟队列是一种使用Redis实现的消息队列,本文主要介绍了Redis延迟队列的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录一、什么是 Redis 延迟队列二、实现原理三、Java 代码示例四、注意事项五、使用 Redi

锐捷和腾达哪个好? 两个品牌路由器对比分析

《锐捷和腾达哪个好?两个品牌路由器对比分析》在选择路由器时,Tenda和锐捷都是备受关注的品牌,各自有独特的产品特点和市场定位,选择哪个品牌的路由器更合适,实际上取决于你的具体需求和使用场景,我们从... 在选购路由器时,锐捷和腾达都是市场上备受关注的品牌,但它们的定位和特点却有所不同。锐捷更偏向企业级和专

hdu1180(广搜+优先队列)

此题要求最少到达目标点T的最短时间,所以我选择了广度优先搜索,并且要用到优先队列。 另外此题注意点较多,比如说可以在某个点停留,我wa了好多两次,就是因为忽略了这一点,然后参考了大神的思想,然后经过反复修改才AC的 这是我的代码 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<

poj 3190 优先队列+贪心

题意: 有n头牛,分别给他们挤奶的时间。 然后每头牛挤奶的时候都要在一个stall里面,并且每个stall每次只能占用一头牛。 问最少需要多少个stall,并输出每头牛所在的stall。 e.g 样例: INPUT: 51 102 43 65 84 7 OUTPUT: 412324 HINT: Explanation of the s