資料流中的中位數
阿新 • • 發佈:2020-08-16
題目描述
如何得到一個數據流中的中位數?如果從資料流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從資料流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。
思路
- 思路一:
維護一個數組,每次加入後,進行排序,當總元素個數為奇數時,中位數就是陣列中間的元素;當總元素個數為偶數時,中位數就是陣列中間元素和前一個元素的平均數。
-
思路二:
維護一個大頂堆,一個小頂堆,且保證兩點:
小頂堆裡的元素全大於大頂堆裡的元素;
兩個堆個數的差值小於等於1;
當insert的數字個數為奇數時:使小頂堆個數比大頂堆多1;當insert的數字個數為偶數時,使大頂堆個數跟小頂堆個數一樣;
當總元素個數為奇數時,中位數就是小頂堆堆頂;當總元素個數為偶數時,中位數就是兩個個堆堆頂平均數。
程式碼實現
package Tree; import java.util.ArrayList; import java.util.Collections; import java.util.PriorityQueue; /** * 資料流中的中位數 * 如何得到一個數據流中的中位數?如果從資料流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。 * 如果從資料流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。 */ public class Solution43 { ArrayList<Integer> list = new ArrayList<>(); // 大頂堆 PriorityQueue<Integer> maxHeap = new PriorityQueue<>((o1, o2) -> o2 - o1); // 小頂堆,並且大頂堆元素都大於小頂堆 PriorityQueue<Integer> minHeap = new PriorityQueue<>(); // 當前資料流讀入的元素個數 int N = 0; public static void main(String[] args) { Solution43 solution43 = new Solution43(); solution43.Insert_2(3); System.out.println(solution43.GetMedian_2()); solution43.Insert_2(4); System.out.println(solution43.GetMedian_2()); } /** * 維護兩個堆,一個大頂堆、一個小頂堆 * * @param val */ public void Insert_2(Integer num) { // 插入要保證兩個堆存於平衡狀態 if (N % 2 == 0) { // N 為偶數的情況下插入到小頂堆。 // 因為大頂堆元素都要大於小頂堆,但是新插入的元素不一定比小頂堆元素來的大, // 因此需要先將元素插入小頂堆,然後利用小頂堆為大頂堆的特點,取出堆頂元素即為最大元素,此時插入大頂堆 maxHeap.offer(num); minHeap.offer(maxHeap.poll()); } else { minHeap.offer(num); maxHeap.offer(minHeap.poll()); } N++; } public Double GetMedian_2() { if (N % 2 == 0) { return (maxHeap.peek() + minHeap.peek()) / 2.0; } else { return (double) minHeap.peek(); } } //--------------------------------------------------------------------------------------------------------------------------------------------- /** * 維護陣列,加入時排序 * * @param num */ public void Insert(Integer num) { list.add(num); Collections.sort(list); } public Double GetMedian() { int n = list.size(); if (n % 2 == 0) { return Double.valueOf((list.get(n / 2) + list.get(n / 2 - 1)) / 2.0); } else { return Double.valueOf(list.get(n / 2)); } } }