这是一个关于面试的问题。设计一个类,该类可存储整数并提供两个操作:
void insert(int k) int getMedian()
我猜可以使用二叉搜索树(BST)来实现,使得 insert
的时间复杂度为 O(logN),getMedian
的时间复杂度也为 O(logN)(对于getMedian
,需要为每个节点添加其左/右子节点的数量)。
现在我想知道是否有更高效的解法,是否存在更优秀的算法。
这是一个关于面试的问题。设计一个类,该类可存储整数并提供两个操作:
void insert(int k) int getMedian()
我猜可以使用二叉搜索树(BST)来实现,使得 insert
的时间复杂度为 O(logN),getMedian
的时间复杂度也为 O(logN)(对于getMedian
,需要为每个节点添加其左/右子节点的数量)。
现在我想知道是否有更高效的解法,是否存在更优秀的算法。
左堆
和右堆
。左堆
是一个最大堆
。右堆
是一个最小堆
。x
小于左堆
的根节点,则将x
插入到左堆
。x
插入到右堆
。左堆
的元素数量比右堆
的元素数量多1,则从左堆
中提取最大值并将其插入到右堆
中。右堆
的元素数量比左堆
的元素数量多,则从右堆
中提取最小值并将其插入到左堆
中。中位数始终是左堆
的根节点。
因此,插入操作的时间复杂度为O(lg n)
,获取中位数的时间复杂度为O(1)
。
如果您在插入时使用专门用于整数的排序算法(http://en.wikipedia.org/wiki/Sorting_algorithm),并从O < O(log(n))中选择候选项,并使用数组,则它是否能够击败执行排序的整数数组,然后获取中位数将取一半大小的索引将是O(1),不是吗?我觉得可能比log(n) + log(n)更好。
此外,通过更加灵活,根据输入的属性(输入是否几乎排序或不排序等)更改排序算法,可以提高性能。
我在计算机科学方面基本上是自学成才,但这就是我会做的方式:简单就是更好。
insert
是O(n)
的影响,但如果存储的值的数量很少,这可能是最好的方法。 - Steve Jessop(log n)
层深处,因为它是右子树的最左边节点或者左子树的最右边节点。因此,为了以 O(1)
的时间访问中位数,您需要追踪的不仅仅是根节点和子树的大小,但仅靠根节点就足以实现 O(log n)
时间复杂度。 - Steve Jessop
getMedian
改进到O(1)
:每次插入后查找中位数(这不会影响复杂度),并将其存储起来。 - Steve JessopgetMedian
改进为O(1)? - Michaelint currentMedian;
。在将元素插入二叉搜索树后,立即找到新的中位数,并将该值存储到currentMedian
中,然后再从insert
函数返回。然后你可以实现int getMedian() { return currentMedian; }
,这样时间复杂度为O(1)
。 - Steve Jessop