【剑指offer】【堆】41. 数据流中的中位数
题目链接:https://leetcode-cn.com/problems/shu-ju-liu-zhong-de-zhong-wei-shu-lcof/
没有排序的数组
同面试题39题,利用分治的思想找出数组的中位数
| 插入 | 找中位数 | |
|---|---|---|
| 时间复杂度 | O(1) | O(n) |
排序数组
利用一个排序的数组,数字进来以后插入到合适的位置,时间复杂度O(n)
| 插入 | 找中位数 | |
|---|---|---|
| 时间复杂度 | O(n) | O(1) |
排序链表
利用两个指针分别指向链表的中间节点,链表中有偶数个数,指向同一个节点;奇数个数,指向不同节点;
| 插入 | 找中位数 | |
|---|---|---|
| 时间复杂度 | O(n) | O(1) |
二叉搜索树
二叉搜索树可以把插入新数据的平均时间降到O(logn);但是当二叉搜索树极度不平衡时,就退化成了一个排序的链表,插入新数据的时间复杂度仍然是O(n);为了得到中位数,可以再二叉树的节点中添加一个表示子树节点数目的字段,通过这个字段,可以再平均O(logn)时间内找到中位数,但是最差情况仍需要O(n)
| 插入 | 找中位数 | |
|---|---|---|
| 时间复杂度 | 平均O(logn) 最差O(n) | 平均O(logn) 最差O(n) |
平衡的二叉搜索树
| 插入 | 找中位数 | |
|---|---|---|
| 时间复杂度 | O(logn) | O(1) |
最大堆和最小堆
如果容器中的数字已经排好序了,p1和p2分别指向中间的节点;奇数时指向同一个节点,偶数时指向不同节点;然后我们将容器分割成两部分,0~p1是一部分 p2~n是一部分;可以发现p1是左边的最大值,p2是右边的最小值;只要能保证,容器左边的数据都小于右边的数据,即使两边的数据没有排序,也可以根据左边最大的数以及右边最小的数得到中位数;
因此,可以维护一个最大堆,维护一个最小堆;用最大堆实现左边数据容器,用最小堆实现右边数据容器;
| 插入 | 找中位数 | |
|---|---|---|
| 时间复杂度 | O(logn) | O(1) |
所有数维护成两个集合,小根堆和大根堆;大根堆和小根堆的堆顶为数据流的中间的两个数;规定,如果有奇数个数,小根堆比大根堆多一个数;
- 每次将要插入的数,插入到大根堆中
- 如果大根堆堆顶的元素比小根堆堆顶元素大,那么将大根堆堆顶元素弹出,放入小根堆;将小根堆堆顶元素弹出,放入大根堆;
- 如果大根堆的元素数比小根堆的元素数多2,那么将大根堆的堆顶弹出,放入小根堆;
class MedianFinder {
public:
/** initialize your data structure here. */
MedianFinder() {
}
priority_queue<int> max_heap;
priority_queue<int, vector<int>, greater<int>> min_heap;
void addNum(int num) {
//当前元素插入到大根堆;
max_heap.push(num);
//如果小根堆堆顶元素小于大根堆堆顶元素
while(min_heap.size() && min_heap.top() < max_heap.top())
{
//小根堆和大根堆堆顶元素交换
auto minv =min_heap.top(), maxv = max_heap.top();
min_heap.pop(), max_heap.pop();
max_heap.push(minv), min_heap.push(maxv);
}
//如果大根堆的元素数目比小根堆元素数目多2及以上
if(max_heap.size() > min_heap.size() + 1)
{
//将大根堆的元素弹出,放入小根堆
min_heap.push(max_heap.top());
max_heap.pop();
}
}
double findMedian() {
//奇数个数
if(max_heap.size() + min_heap.size() & 1) return max_heap.top();
//偶数个数
return (max_heap.top() + min_heap.top()) / 2.0;
}
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder* obj = new MedianFinder();
* obj->addNum(num);
* double param_2 = obj->findMedian();
*/
知识的价值不在于占有,而在于使用

浙公网安备 33010602011771号