问题是:
找到固定大小(k)数字的大数据(n个数字)的中位数
我的想法是:
保持2堆,最小堆数用于小于当前中位数的数字,最小堆数用于大于当前中位数的数字
主要概念是 FIND 其中一个堆中的前一个元素的第一个元素(取决于它是<或>当前中位数),并将其替换为我们遇到的新元素。 />
现在修改如make | size(heap1) - size(heap2)| = 1或0,因为中位数是平均值。顶部元素,如果size1!= size2,则是堆的顶部元素,大小为>其他的大小。
我面临的问题是时间复杂度增加,因为发现元素花费O(n)时间总共O(n*k)
,所以我无法达到所需的复杂度{{ 1}}(如问题来源所要求的那样)。
如果不使用额外的空间,应该如何减少?
编辑:输入:1 4 3 5 6 2,k = 4
中位数:
从1 4 3 5 =(4 + 3)/ 2
从4 3 5 6 =(4 + 5)/ 2
从3 5 6 2 =(3 + 5)/ 2
答案 0 :(得分:1)
您可以使用order-statistic tree来解决此问题,这是一个BST,其中包含一些其他信息,可以在O(log n )时间内查找中位数,分位数和其他顺序统计信息。 n 元素的树。
首先,使用第一个 k 元素构造一个OST。然后,循环:
如果树是自平衡的,这些步骤中的每一步都需要O(log k ),因为我们保持树永远不会超过 k 的不变量,还给出了O( k )辅助空间。预处理需要O( k log k )时间,而循环重复 n + 1 - k 次总时间为O( n log k )。
答案 1 :(得分:1)
如果你能找到一个平衡的树实现,它可以让你有效地访问中心元素,你应该使用它。你也可以像你建议的那样用堆来做这件事,只要你保留一个额外的长度为k的数组,告诉你窗口中的每个元素在堆中的位置,以及它在哪个堆中。你将不得不修改它维护堆以在其移动时更新此数组的代码,但堆代码更容易编写并且比平衡树代码小很多。然后,您不需要搜索所有堆以删除刚刚离开窗口边缘的项目,并且成本降低到n log k。
答案 2 :(得分:0)
这个问题看起来像你在dijkstra最短路径中有效实现的那个问题,我们需要删除(在dijkstra的情况下更新)一个不在堆顶部的元素。但是你可以使用相同的工作来这个问题,但额外的空间复杂性。首先,您不能使用内置堆库,创建自己的堆数据结构,但维护指向堆中每个元素的指针,以便在添加或删除元素时更新指向每个元素的指针。因此,在计算出前k个元素的中位数后,根据是否大于或小于使用指针的中位数,直接从堆中删除第一个元素(min或max),然后在该位置使用heapify
。然后堆的大小发生变化,然后你可以使用与调整堆大小和计算中位数相同的逻辑来获得新的中位数。
Heapify
需要O(logk)
,因此您的总费用为O(n*logk)
,但需要O(n)
个更多的指针空间。