原题
https://leetcode-cn.com/problems/find-median-from-data-stream/
思路
使用两个优先队列 PriorityQueue
一个用来存储中位数前边的数据,要求从大到小排列,命名为queueMin
一个用来存储中位数后边的数据,要求从小到大排列,命名为queueMax
这样两个queue.peek()
用来计算中位数
下面讨论列表的奇偶性
- 奇数
- 右边多存储一个元素,也就是
queueMin.size() + 1 == queueMax.size()
- 得到的中位数就是
queueMax.peek()
- 右边多存储一个元素,也就是
- 偶数
- 左边和右边存储的元素数量一致,也就是
queueMin.size() == queueMax.size()
- 得到的中位数就是
(queueMin.peek() + queueMax.peek()) / 2.0
- 左边和右边存储的元素数量一致,也就是
插入元素的时候
queueMax.isEmpty()
num >= queueMax.peek()
就往右边队列queueMax
插入数据
其余往左边插入
注意:插入数据的同时还要维护queueMin.size()
和queueMax.size()
(1)向右边queueMax
插入的时候,queueMax.size() > queueMin.size()+1
的时候,就要把queueMax.poll()
添加到queueMin
中
(2)向左边queueMin
插入的时候,queueMin.size() > queueMax.size()
的时候,就要把queueMin.poll()
添加到queueMax
中
题解
package com.ivydad.test;
import java.util.PriorityQueue;
/**
* @Author: kun.zhang@ivydad.com
* @Description: TODO
* @DateTime: 2021/8/27 6:03 下午
**/
public class MedianFinder {
// 存储中位数前边那一部分,从大到小排列
PriorityQueue<Integer> queueMin;
// 存储中位数后边那一部分,从小到大排列
PriorityQueue<Integer> queueMax;
public MedianFinder() {
queueMin = new PriorityQueue<>((a,b) -> b-a);
queueMax = new PriorityQueue<>((a,b) -> a-b);
}
// 奇数:后段队列多一个
// 偶数:两个队列等长
public void addNum(int num) {
if (queueMax.isEmpty() || queueMax.peek() <= num) {
queueMax.offer(num);
if (queueMax.size() > queueMin.size() + 1) {
queueMin.offer(queueMax.poll());
}
} else {
queueMin.offer(num);
if (queueMin.size() > queueMax.size()) {
queueMax.offer(queueMin.poll());
}
}
}
public double findMedian() {
if (queueMin.size() == queueMax.size()) {
return (queueMin.peek() + queueMax.peek())/2.0;
} else {
return queueMax.peek();
}
}
public static void main(String[] args) {
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1);
medianFinder.addNum(2);
System.out.println(medianFinder.findMedian());
medianFinder.addNum(3);
System.out.println(medianFinder.findMedian());
}
}