【leetcode】Find Median From Data Stream

文章介绍了如何使用大根堆和小根堆数据结构来实现实时计算数据流中的中位数。MedianFinder类通过维护两个堆,保证它们的大小差不超过1,从而能快速找到当前的中位数。在添加新数时,根据新数与大根堆堆顶的关系决定其进入哪个堆,然后通过balance方法保持堆的平衡。这样设计可以高效地处理动态数据并找到近似的中位数。
摘要由CSDN通过智能技术生成

参考资料:左神算法课+《剑指offer》
295. Find Median from Data Stream
The median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value, and the median is the mean of the two middle values.

For example, for arr = [2,3,4], the median is 3.
For example, for arr = [2,3], the median is (2 + 3) / 2 = 2.5.
Implement the MedianFinder class:

MedianFinder() initializes the MedianFinder object.
void addNum(int num) adds the integer num from the data stream to the data structure.
double findMedian() returns the median of all elements so far. Answers within 10-5 of the actual answer will be accepted.

Example 1:
Input
[“MedianFinder”, “addNum”, “addNum”, “findMedian”, “addNum”, “findMedian”]
[[], [1], [2], [], [3], []]
Output
[null, null, null, 1.5, null, 2.0]

Explanation
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1); // arr = [1]
medianFinder.addNum(2); // arr = [1, 2]
medianFinder.findMedian(); // return 1.5 (i.e., (1 + 2) / 2)
medianFinder.addNum(3); // arr[1, 2, 3]
medianFinder.findMedian(); // return 2.0

观察到:小于中位数的数的个数 与 大于中位数的数的个数 相差 <=1 ; 如果对数组排序的话,小于中位数的数 总是 位于 中位数 左侧,大于中位数的数总是 位于中位数右侧。

思路:建立大根堆、小根堆,第一个数据来到后,先进大根堆;之后的数,与大根堆的堆顶比较,决定它进大根堆还是小根堆。具体地,如果新数小于大根堆堆顶,那么进大根堆;如果新数大于大根堆堆顶,那么进小根堆。然后,调整两个堆(balance()),使得二者size相差≤1,这样才能“暴露”出两个“预备中位数“(指大根堆、小根堆的堆顶),便于找出中位数。

《剑指offer》给出的思路与之类似,但是 在维护两个堆大小的调整上有些别扭(个人感觉),而 算法课 给出的代码更自然——先往大根堆里加,后来的数与大根堆堆顶比较,加入到相应的堆中后,用balance函数一起调整两个堆的size。

class MedianFinder{
		private PriorityQueue<Integer> minh;
		private PriorityQueue<Integer> maxh;
		
		public MedianFinder()
		{
			minh = new PriorityQueue<>((a,b)->a-b);
			maxh = new PriorityQueue<>((b,a)->b-a);
			
		}
		
		public void addNum(int num)
		{
			if(maxh.isEmpty())
			{
				maxh.add(num);
			}else
			{
				if(maxh.peek()>=num)
				{
					maxh.add(num);
				}else {
					minh.add(num);
				}
			}
			balance();
		}
		
		public void balance()
		{
			if(maxh.size()-minh.size()==2)
			{
				minh.add(maxh.poll());
			}
			if(minh.size()-maxh.size()==2)
			{
				maxh.add(minh.poll());
			}
		}
		
		public double findMedian()
		{
			if(((maxh.size()+minh.size())&1)==1)
			{
				// odd
				return maxh.size()>minh.size()?maxh.peek():minh.peek();
			}else {
				return (double)(maxh.peek()+minh.peek())/2;
			}
		}
		
		
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值