Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.
Examples:
[2,3,4] , the median is 3
[2,3], the median is (2 + 3) / 2 = 2.5
Design a data structure that supports the following two operations:
void addNum(int num)- Add a integer number from the data stream to the data structure.double findMedian()- Return the median of all elements so far.
Example:
addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2
C Solution:
struct Heap {
int *heap;
int top;
int size;
bool (*cmp)(int a, int b);
};
typedef struct {
struct Heap *p;
struct Heap *q;
} MedianFinder;
bool smaller(int a, int b) {
return a < b;
}
bool bigger(int a, int b) {
return a > b;
}
struct Heap *create(bool (*cmp)(int, int)) {
struct Heap *res = malloc(sizeof(struct Heap));
res->size = 1000;
res->top = 1;
res->heap = malloc(res->size * sizeof(int));
res->cmp = cmp;
return res;
}
/** initialize your data structure here. */
MedianFinder* medianFinderCreate() {
MedianFinder *obj = malloc(sizeof(MedianFinder));
obj->p = create(smaller);
obj->q = create(bigger);
return obj;
}
int pop(struct Heap *h) {
int res = h->heap[1];
h->heap[1] = h->heap[--h->top];
int root = 1, child = 2;
while (child < h->top) {
if (child + 1 < h->top && h->cmp(h->heap[child], h->heap[child + 1])) child++;
if (!h->cmp(h->heap[root], h->heap[child])) return res;
int tmp = h->heap[root];
h->heap[root] = h->heap[child];
h->heap[child] = tmp;
root = child;
child = root * 2;
}
return res;
}
void push(struct Heap *h, int num) {
if (h->top == h->size) {
h->size += 1000;
h->heap = realloc(h->heap, h->size * sizeof(int));
}
h->heap[h->top++] = num;
int cur = h->top - 1, root = cur / 2;
while (root && h->cmp(h->heap[root], h->heap[cur])) {
int tmp = h->heap[root];
h->heap[root] = h->heap[cur];
h->heap[cur] = tmp;
cur = root;
root = cur / 2;
}
}
void medianFinderAddNum(MedianFinder* obj, int num) {
push(obj->p, num);
push(obj->q, pop(obj->p));
struct Heap *tmp = obj->p;
obj->p = obj->q;
obj->q = tmp;
}
double medianFinderFindMedian(MedianFinder* obj) {
if (obj->p->top == obj->q->top) return (obj->p->heap[1] + obj->q->heap[1]) / 2.0;
if (obj->p->top > obj->q->top) return obj->p->heap[1];
return obj->q->heap[1];
}
void medianFinderFree(MedianFinder* obj) {
free(obj->p->heap);
free(obj->q->heap);
free(obj->p);
free(obj->q);
free(obj);
}
/**
* Your MedianFinder struct will be instantiated and called as such:
* struct MedianFinder* obj = medianFinderCreate();
* medianFinderAddNum(obj, num);
* double param_2 = medianFinderFindMedian(obj);
* medianFinderFree(obj);
*/
Summary:
- Using two heap, left heap records the max of the half, right heap records the min of the other half.
- The time complexity is O(lg(N)) for add, O(1) for find.
- 119ms, 75%.
- From the very beginning to the end, keep the difference of the length of the two heaps under 1.
- With swaping the pointers of the two heaps after adding.
- Better than enough.
LeetCode: 295. Find Median from Data Stream





近期评论