题目地址:
https://www.lintcode.com/problem/find-median-from-data-stream/description
给定一个数组,返回一个数组,每一位为给定数组的 [ 0 , i ] [0,i] [0,i]区间的中位数。这里,一个数组的中位数定义是,首先数组排序好,如果数组长度为奇数,则中位数就是中间数;否则是中间偏左一位的数。
思路是,用对顶堆,一个最大堆保存较小的一半数,另一个最小堆保存较大的一半数。新来一个数时,先判断其属于较大的一半还是较小的一半,然后把它加进对应的堆中,接着就开始调整两个堆的大小,使得大顶堆永远比小顶堆的size相等或者大 1 1 1。每次取中位数时只需取大顶堆堆顶即可。代码如下:
import java.util.PriorityQueue;
public class Solution {
/**
* @param nums: A list of integers
* @return: the median of numbers
*/
public int[] medianII(int[] nums) {
// write your code here
// 开两个堆,一个大顶堆一个小顶堆
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((i1, i2) -> i2 < i1 ? -1 : 1), minHeap = new PriorityQueue<>();
int[] res = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
res[i] = add(nums[i], maxHeap, minHeap);
}
return res;
}
// 作用是向对顶堆里加入数num,同时调整堆的size,并最后返回中位数
private int add(int num, PriorityQueue<Integer> maxHeap, PriorityQueue<Integer> minHeap) {
// 如果大顶堆为空,则直接加进大顶堆,然后返回
if (maxHeap.isEmpty()) {
maxHeap.offer(num);
return num;
}
// 接着判断num属于哪一半,加入对应的堆
if (num <= maxHeap.peek()) {
maxHeap.offer(num);
} else {
minHeap.offer(num);
}
// 接着调整两个堆的size
if (maxHeap.size() < minHeap.size()) {
maxHeap.offer(minHeap.poll());
} else if (maxHeap.size() > minHeap.size() + 1) {
minHeap.offer(maxHeap.poll());
}
// 返回中位数
return maxHeap.peek();
}
}
时间复杂度 O ( n log n ) O(n\log n) O(nlogn),空间 O ( n ) O(n) O(n)。