数据流中的中位数python_剑指offer 数据流的中位数

题目描述:

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

题目分析:

对于数据流,对应的就是在线算法了,一道很经典的题目就是在1亿个数中找到最大的前100个数,这是一道堆应用题,找最大的前100个数,那么我们就创建一个大小为100的最小化堆,每来一个元素就与堆顶元素比较,因为堆顶元素是目前前100大数中的最小数,前来的元素如果比该元素大,那么就把原来的堆顶替换掉。

那么对于这一道题呢?如果单纯的把所有元素放到一个数组里,每次查找中位数最快也要O(n),综合下来是O(n^2)的复杂度。可以利用上面例子中的想法,用一个最大堆来维护当前前n/2小的元素,那么每次找中位数只到取出堆顶就可以了。但是,有一个问题,数据要动态增长,有可能之前被替换掉的元素随着元素的增加又跑回来了,所以不能单纯得向上题一样把元素丢掉,这里可以再用一个最小化堆来存前n/2大的元素。

Python版本示例代码:

class Solution:

def __init__(self):

self.littleValueMaxHeap = []

self.bigValueMinHeap = []

self.maxHeapCount = 0

self.minHeapCount = 0

def Insert(self, num):

def cmpMaxHeap(a, b):

return a > b

def cmpMinHeap(a, b):

return a < b

if self.maxHeapCount > self.minHeapCount:

self.minHeapCount += 1

if num < self.littleValueMaxHeap[0]:

tmpNum = self.littleValueMaxHeap[0]

self.adjustHeap(num, self.bigValueMinHeap, cmpMinHeap)

self.createHeap(tmpNum, self.bigValueMinHeap, cmpMinHeap)

else:

self.createHeap(num, self.bigValueMinHeap, cmpMinHeap)

else:

self.maxHeapCount += 1

if len(self.littleValueMaxHeap) == 0:

self.createHeap(num, self.littleValueMaxHeap, cmpMaxHeap)

else:

if self.bigValueMinHeap[0] < num:

tmpNum = self.bigValueMinHeap[0]

self.adjustHeap(num, self.littleValueMaxHeap, cmpMaxHeap)

self.createHeap(tmpNum, self.littleValueMaxHeap, cmpMaxHeap)

else:

self.createHeap(num, self.littleValueMaxHeap, cmpMaxHeap)

def GetMedian(self):

if self.minHeapCount < self.maxHeapCount:

return self.littleValueMaxHeap[0]

else:

return (self.littleValueMaxHeap[0] + self.bigValueMinHeap[0]) / 2

def createHeap(self, num, heap, cmpfun):

heap.append(num)

tmpIndex = len(heap) - 1

while tmpIndex:

parentIndex = (tmpIndex - 1) // 2

if cmpfun(heap[tmpIndex], heap[parentIndex]):

heap[parentIndex], heap[tmpIndex] = heap[tmpIndex], heap[parentIndex]

tmpIndex = parentIndex

else:

break

def adjustHeap(self, num, heap, cmpfun):

if num < heap[0]:

maxHeapLen = len(heap)

heap[0] = num

tmpIndex = 0

while tmpIndex < maxHeapLen:

leftIndex = tmpIndex * 2 + 1

rightIndex = tmpIndex * 2 + 2

largerIndex = 0

if rightIndex < maxHeapLen:

largerIndex = rightIndex if cmpfun(heap[rightIndex], heap[leftIndex]) else leftIndex

elif leftIndex < maxHeapLen:

largerIndex = leftIndex

else:

break

if cmpfun(heap[largerIndex], heap[tmpIndex]):

heap[largerIndex], heap[tmpIndex] = heap[tmpIndex], heap[largerIndex]

tmpIndex = largerIndex

else:

break

Java版本示例代码:

import java.util.PriorityQueue;

import java.util.Comparator;

public class Solution {

PriorityQueue pqMax = new PriorityQueue(new Comparator(){

@Override

public int compare(Integer o1, Integer o2){

return o2 - o1;

}

});

PriorityQueue pqMin = new PriorityQueue();

public void Insert(Integer num) {

if(pqMax.size() == 0 || num < pqMax.peek()){

pqMax.offer(num);

}else{

pqMin.offer(num);

}

if(Math.abs(pqMax.size() - pqMin.size()) > 1){

if(pqMax.size() > pqMin.size()){

pqMin.offer(pqMax.poll());

}else{

pqMax.offer(pqMin.poll());

}

}

}

public Double GetMedian() {

int count = pqMax.size() + pqMin.size();

if(count % 2 == 1){

if(pqMax.size() > pqMin.size()){

return 1.0 * pqMax.peek();

}else{

return 1.0 * pqMin.peek();

}

}else{

return (pqMax.peek() + pqMin.peek())/2.0;

}

}

}

Tips

插入元素:add()、offer()

删除元素:poll()

获取队头元素:peek()

获取队列大小:size()

清空队列:clear()

是否包含某个元素:contains()

清除一个指定元素:remove()

优先队列默认按从小到大的顺序排列,如果需要一个大顶堆的话,需要重写compar方法。

Note

这个题目也可以用先排序再取中位数的方式,只是这样做对数据量大的时候会超时。在python中可以直接调用.sort()进行排序

class Solution:

def __init__(self):

self.data = []

def Insert(self, num):

self.data.append(num)

self.data.sort()

def GetMedian(self, data):

length = len(self.data)

if length % 2 == 0:

return (self.data[length // 2] + self.data[length // 2 -1]) / 2.0

else:

return self.data[int(length // 2)]欢迎关注,一起学习

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 python ,如果要查找海量数据的中位数,可以使用 heapq 库的函数 nsmallest() 和 nlargest()。 首先,将所有数据读入内存,然后使用 heapq.heapify() 将数据堆化。接下来,调用 nsmallest() 和 nlargest() 来获取最小的 k 个数和最大的 k 个数。最后,根据这 k 个数的大小关系,就可以得出中位数。 例如,如果 k=len(data)//2,那么中位数就是最小的 k 个数的最大值。 这种方法的时间复杂度是 O(n log n),空间复杂度是 O(n)。 注意,如果要查找的数据量太大,无法一次性读入内存,就需要使用其他方法,例如流式计算。 ### 回答2: 对于海量数据找中位数问题,可以使用堆排序算法来解决。 首先,将海量数据分割成多个小块,每个小块可以使用快速排序算法进行排序,再将排序好的小块使用堆数据结构进行合并。 然后,使用一个最大堆和一个最小堆来存储数据。最大堆保存一半较小的数据,最小堆保存一半较大的数据。具体实现方式如下: 1. 初始化最大堆和最小堆为空堆。 2. 依次读取海量数据,并根据数据的大小来决定插入最大堆还是最小堆。 - 如果最大堆的大小小于最小堆的大小,则将数据插入最大堆,并对最大堆进行调整,保证最大堆的堆顶(即最大值)小于等于最小堆的堆顶(即最小值)。 - 如果最大堆的大小大于最小堆的大小,则将数据插入最小堆,并对最小堆进行调整,保证最小堆的堆顶(即最小值)大于等于最大堆的堆顶(即最大值)。 3. 当读取完全部数据后,根据最大堆和最小堆的大小来决定中位数的位置。 - 如果最大堆的大小等于最小堆的大小,则中位数为最大堆的堆顶和最小堆的堆顶的平均值。 - 如果最大堆的大小大于最小堆的大小,则中位数为最大堆的堆顶。 - 如果最大堆的大小小于最小堆的大小,则中位数为最小堆的堆顶。 通过这种方式,不需要将全部数据加载到内存,可以在读取数据的同时进行排序和求解中位数,从而适用于海量数据的情况。 ### 回答3: 在Python,处理海量数据找中位数的一种常见方法是使用堆。 首先,我们需要了解中位数的概念。对于一个有序的数据集,中位数将数据划分为两个等长子集,左子集的所有元素都小于等于右子集的所有元素。如果数据集有奇数个元素,则中位数间的那个元素;如果有偶数个元素,则中位数间两个元素的平均值。 对于海量数据,我们无法直接将其全部加载到内存进行排序,因此需要使用堆来解决这个问题。堆是一种特殊的树形数据结构,具有以下特点:每个节点的值都大于(或小于)其子节点的值。 我们可以使用两个堆来实现,一个大根堆和一个小根堆。首先,将数据集的前一半数据插入到大根堆,将剩余的一半数据插入到小根堆。这样可以确保大根堆的所有元素都小于小根堆的元素。然后,我们可以根据数据集的大小,采取不同的策略来计算中位数。 如果数据集的大小是奇数,中位数就是小根堆的堆顶元素。如果数据集的大小是偶数,中位数就是大根堆的堆顶元素和小根堆的堆顶元素的平均值。 在实际实现,我们可以使用Python的heapq模块来操作堆。具体的步骤如下: 1. 利用heapq模块的heapify函数,将数据集前一半的元素插入大根堆,将剩余的一半元素插入小根堆。 2. 如果数据集的大小是奇数,直接返回小根堆的堆顶元素。 3. 如果数据集的大小是偶数,返回大根堆的堆顶元素和小根堆的堆顶元素的平均值。 对于海量数据来说,可以将数据分块读取,每次读取一部分数据,然后进行堆的操作。通过这种方式,可以有效地处理海量数据,找到中位数

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值