76、堆-数据流的中位数

2024-05-01 20:12
文章标签 数据流 76 中位数

本文主要是介绍76、堆-数据流的中位数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

思路:

        这个问题是动态数据流中位数查找问题。在数据流中,数据是逐个到来的,而我们需要在任何时候快速返回已有数据的中位数。中位数是将数据集分成两个等长的子集,一个包含所有较小的元素而另一个包含所有较大的元素。

为了高效解决这个问题,我们可以使用两个优先队列(堆):

  • 一个最大堆(maxQueue),用来存储当前所有元素中较小的一半,它能够保证在堆顶的是这个子集中最大的元素。
  • 一个最小堆(minQueue),用来存储较大的一半,它能够保证在堆顶的是这个子集中最小的元素。

这样设计的原因是:

最大堆和最小堆的堆顶元素可以视为中位数或中位数的候选值,因为这两个元素正好将整个数据集分为两个等长的部分,或者其中一个部分多一个元素(当数据总数是奇数时)。
插入操作(addNum)可以保持两个堆的大小平衡(即数量相等或仅差一个元素),这样可以确保中位数总是处于堆顶,可以在常数时间内被检索到。
当数据总数为偶数时,中位数是两个堆顶元素的平均值;当数据总数为奇数时,中位数是元素多的那个堆的堆顶元素。
在addNum方法中,每次添加一个新元素时,我们首先判断它应该属于哪一个子集:

如果新元素小于等于最大堆的堆顶元素,或者最大堆为空,这意味着这个新元素属于较小的一半,因此应该加入最大堆。
否则,它属于较大的一半,应该加入最小堆。
加入元素后,我们可能需要重新平衡两个堆以确保它们的大小满足要求。如果任一堆的大小超过另一堆的大小超过1,我们将堆顶元素移动到另一堆以恢复平衡。

在findMedian方法中,我们根据两个堆的大小关系来确定中位数:

如果两个堆的大小相等,这意味着元素总数是偶数,我们返回两个堆顶元素的平均值作为中位数。
如果两个堆的大小不等,这意味着元素总数是奇数,我们返回元素较多的那个堆的堆顶元素作为中位数。
整体上,这个设计利用了最大堆和最小堆各自的性质,以及它们在维护中位数方面的互补性,从而提供了一个既高效又简洁的解决方案。

class MedianFinder {// 用于存储较大一半元素的小顶堆。PriorityQueue<Integer> minQueue;// 用于存储较小一半元素的大顶堆。PriorityQueue<Integer> maxQueue;// MedianFinder 类的构造函数。public MedianFinder() {// 初始化 minQueue 为小顶堆。minQueue = new PriorityQueue<>();// 初始化 maxQueue 为大顶堆,使用自定义比较器来逆序元素。maxQueue = new PriorityQueue<>((a, b) -> b - a);}// 将数字添加到数据结构中的方法。public void addNum(int num) {// 如果 maxQueue 是空的,直接将数字添加到 maxQueue。if (maxQueue.isEmpty()) {maxQueue.add(num);} else {// 根据 maxQueue 的顶部元素决定将数字添加到 minQueue 或 maxQueue。if (maxQueue.peek() >= num) {maxQueue.add(num);} else {minQueue.add(num);}}// 如果必要的话,调整堆的大小,确保两个堆的大小差不多于1。if (maxQueue.size() == minQueue.size() + 2) {minQueue.add(maxQueue.poll());}if (minQueue.size() == maxQueue.size() + 2) {maxQueue.add(minQueue.poll());}}// 查找当前添加的数字的中位数的方法。public double findMedian() {// 如果两个堆的大小相同,中位数是它们顶部元素的平均值。if (maxQueue.size() == minQueue.size()) {return (maxQueue.peek() + minQueue.peek()) / 2.0;} else if (maxQueue.size() > minQueue.size()) {// 如果 maxQueue 的元素更多,中位数是 maxQueue 的顶部元素。return maxQueue.peek() * 1.0;} else {// 如果 minQueue 的元素更多,中位数是 minQueue 的顶部元素。return minQueue.peek() * 1.0;}}
}

这篇关于76、堆-数据流的中位数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

数据流与Bitmap之间相互转换

把获得的数据流转换成一副图片(Bitmap) 其原理就是把获得倒的数据流序列化到内存中,然后经过加工,在把数据从内存中反序列化出来就行了。 难点就是在如何实现加工。因为Bitmap有一个专有的格式,我们常称这个格式为数据头。加工的过程就是要把这个数据头与我们之前获得的数据流合并起来。(也就是要把这个头加入到我们之前获得的数据流的前面)      那么这个头是

微信小程序(一)数据流与数据绑定

一、单向数据流和双向数据流 1、单项数据流:指的是我们先把模板写好,然后把模板和数据(数据可能来自后台)整合到一起形成HTML代码,然后把这段HTML代码插入到文档流里面 优点:数据跟踪方便,流向单一,追寻问题比较方便【主要体现:微信小程序】。 缺点:就是写起来不太方便,如果修改UI界面数据需要维护对应的model对象 2、双向数据流:值和UI是双向绑定的,大家都知道,只要UI里面的值发生

【SGU】 114. Telecasting station 中位数

传送门:【SGU】 114. Telecasting station 题目分析:一个位置多个城市可以看成多个城市在同一位置,然后就可以求中位数了,易知最优的位置一定在中位数上。 代码如下 : #include <map>#include <vector>#include <cstdio>#include <cstring>#include <iostream>

Leetcode每日刷题之76.最小覆盖子串(C++)

1.题目解析 本题的题目是给定两个字符串 s 和 t ,找出在 s 中的某个最小子串保证该子串中包含所以 t 中出现的字母即可,并且该结果是唯一答案,找不到结果就直接返回空串即可   2.算法原理 关于本题的核心思路就是"滑动窗口",具体实现是: 1.首先给定两个指针left和right,使用count统计窗口内有效字符的种类,之所以不是有效字符的个数是因为在最小子串中只要完全包含t中

算法/编程练习:两个有序数组的中位数

算法/编程练习:两个有序数组的中位数 题目来自LeetCode: https://leetcode-cn.com/problems/median-of-two-sorted-arrays/ 题目: 给定两个大小为 n1 和 n2 的有序(升序)数组 nums1 和 nums2 ,找出这两个有序数组的中位数mid。要求算法的时间复杂度为 O(log(m + n))。例如,输入: nu

SQL进阶技巧:给定数字的频率查询中位数 | 中位值计算问题

目录 0 需求描述 1 数据准备 2 问题分析 方法1:按照频率将num值展开,转换成明细表,利用中位值公式 求解      abs(rn - (cnt+1)/2) < 1  方法2:中位值定义 3 小结 0 需求描述 num表: Column NameTypenumintfrequencyint num 是这张表的主键(具有唯一值的列)。这张表的每一行表示某个数字

Linux | 匿名管道和命名管道:进程间通信数据流的桥梁

目录 1、进程间通信目的 2、管道——匿名管道和命名管道 匿名管道 匿名管道的示例代码:将数据写入管道、子进程从管道读取数据并将其输出到bash中 父子进程通过匿名管道建立通信 重点:管道的五个特点 命名管道(也称为FIFO) a. 创建命名管道 - mkfifo() b. 使用open函数打开命名管道文件 c. 读写命名管道- read() 和 write() d. 关闭和

算法--------------------寻找两个有序数组的中位数

题目描述 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。你可以假设 nums1 和 nums2 不会同时为空。示例 1:nums1 = [1, 3]nums2 = [2]则中位数是 2.0示例 2:nums1 = [1, 2]nums2 = [3, 4]则中位数是 (2 + 3)/

leetcode 4:两个排序数组的中位数

寻找中位数,当m+n是奇数时,中位数为第(m+n+1)/2个数,当m+n为偶数时,中位数为第(m+n+1)/2和(m+n+2)/2的平均数 根据整数的取整,我们可以统一为中位数为第(m+n+1)/2和(m+n+2)/2的平均数。 如何使用二分法求两个有序数组的第k个数 首先将数组A和数组B分为left_A(下标为0~k/2-1),right_A,left_B(下标为0~k/2-1),ri