【劍指offer中等部分26】資料流中得中位數(java)
阿新 • • 發佈:2020-12-30
題目描述
如何得到一個數據流中的中位數?如果從資料流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從資料流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用Insert()方法讀取資料流,使用GetMedian()方法獲取當前讀取資料的中位數。
分析
這題挺難的,我是看了別人得文章,理解演算法後,再編了一遍。
關於大小頂堆概念見:https://www.cnblogs.com/lanhaicode/p/10546257.html
主要思路:
主要的思想是:因為要求的是中位數,那麼需要兩個堆,大頂堆用來存較小的數,小頂堆存較大的數,並且保證過程中大小頂堆中資料數目最多相差1,程式碼如下:
import java.util.TreeSet;
public class Solution {
//注意此處要求小頂堆中最小的,都要大於等於大頂堆中最大的,如小頂堆[6,8,9],大頂堆[1,3,4]
//保證大小頂堆中數字個數最多隻能相差1
TreeSet<Integer> max = new TreeSet<Integer>(); //大頂堆,用於存放前面一半的元素(小的)
TreeSet<Integer> min = new TreeSet<Integer>(); //小頂堆,用於存放後面一般的元素(大的)
public void Insert(Integer num) {
if (((max.size() + min.size()) & 1) == 0) { //兩堆相加為偶數,即10,110,1110等,反正第一位不是0,所以&後得0
//num值大於小頂堆中最小的值,則小頂堆根節點值(最小值)放入小頂堆,如num=7,7>6,則將7加入小頂堆,再把6加入大頂堆
if (min.size() > 0 && num > min.first()) {
min.add (num); //值插入小頂堆中
num = min.first();
min.remove(num);//拿出小頂堆中的根節點值,
}
max.add(num);
}else {
//如小頂堆[7,8,9],大頂堆[1,3,4,6],num=5, 5<6,則將6加入小頂堆,變為[6,7,8,9],[1,3,4,5]
if (max.size() > 0 && num < max.last()) {
max.add(num);
num = max.last();
max.remove(num);
}
min.add(num);
}
}
public Double GetMedian() {
int size = max.size() + min.size();
if (size == 0) {
return 0.0;
}
if ((size & 1) == 0) {
return (max.last() + min.first()) / 2.0; //偶數求和,如[6,7,8,9],[1,3,4,5]情況,取(5+6)/2.0
}else {
return (double)max.last();//奇數,如小頂堆[7,8,9],大頂堆[1,3,4,6]情況,取6.0
}
}
}