LeetCode—295. 数据流的中位数(困难)
295. 数据流的中位数(困难)
题目描述: 中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。 例如, [2,3,4] 的中位数是 3 [2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构: void addNum(int num) - 从数据流中添加一个整数到数据结构中。 double findMedian() - 返回目前所有元素的中位数。
考察重点:利用sort.IntSlice完成数组的排序并实现小顶堆,继承IntSlice完成数组的逆序并实现大顶堆; 大小顶堆配合查询中位数;声明大顶堆存放较小的一半元素,堆顶存放上半区最大元素;小顶堆存放较大的一半元素,堆顶存放下半区最小元素;中位数即是二者均值或大顶堆堆顶元素。 go实现大小顶堆
package DataStructure import ( "sort" ) //真小顶堆 type MinHeap struct { sort.IntSlice } func NewMinHeap() *MinHeap { return &MinHeap{ IntSlice: sort.IntSlice{ }} } func (h *MinHeap) Push(a interface{ }) { h.IntSlice = append(h.IntSlice, a.(int)) } func (h *MinHeap) Pop() interface{ } { a := h.IntSlice v := a[len(a)-1] h.IntSlice = a[:len(a)-1] return v } type ReverseIntSlice []int func (x ReverseIntSlice) Len() int { return len(x) } func (x ReverseIntSlice) Less(i, j int) bool { return x[i] > x[j] } func (x ReverseIntSlice) Swap(i, j int) { x[i], x[j] = x[j], x[i] } type MaxHeap struct { ReverseIntSlice } func NewMaxHeap() *MaxHeap { return &MaxHeap{ ReverseIntSlice: ReverseIntSlice{ }} } func (h *MaxHeap) Push(a interface{ }) { h.ReverseIntSlice = append(h.ReverseIntSlice, a.(int)) } func (h *MaxHeap) Pop() interface{ } { a := h.ReverseIntSlice v := a[len(a)-1] h.ReverseIntSlice = a[:len(a)-1] return v } //这只是一个用sort方法仿制的堆,耗时仍然等于对一个数组进行排序 type Heap struct { HeapItem sort.IntSlice } func NewHeap() (h *Heap) { return &Heap{ HeapItem: sort.IntSlice{ }} } func (h *Heap) Push(a int) { h.HeapItem = append(h.HeapItem, a) sort.Sort(h.HeapItem) } func (h *Heap) Pop() int { temp := h.HeapItem[0] h.HeapItem = h.HeapItem[1:] return temp }
实现中位数查找
package leetcodeProject import ( "container/heap" d "DataStructure" ) type MedianFinder struct { MaxItem *d.MaxHeap //声明一个大顶堆,一个小顶堆 大顶堆用来存放前一半比较小的数,小顶堆用来存放后一半比较大的数,即小顶堆堆顶大于大顶堆堆顶 MinItem *d.MinHeap } func Constructor6() MedianFinder { return MedianFinder{ MaxItem: d.NewMaxHeap(), MinItem: d.NewMinHeap()} } /** 先将新元素加入大顶堆,再将大顶堆堆顶元素(最大值)加入小顶堆 始终保证大顶堆元素==小顶堆元素||小顶堆元素+1 否则,将小顶堆堆顶(最小值)加入大顶堆 比如 3,4,1,2 3 3加入大堆 3加入小堆 “小堆多于大堆” 3加入大堆 小: 大:3 4 4加入大堆 4加入小堆 “小堆等于大堆” 小:4 大:3 1 1加入大堆 3加入小堆 “小堆多于大堆” 3加入大堆 小:4 大:1 3 2 2加入大堆 3加入小堆 “小堆等于大堆” 小:4 3 大:1 2 */ func (h *MedianFinder) AddNum(num int) { heap.Push(h.MaxItem, num) heap.Push(h.MinItem, heap.Pop(h.MaxItem).(int)) if h.MaxItem.Len() < h.MinItem.Len() { heap.Push(h.MaxItem, heap.Pop(h.MinItem).(int)) } } func (h *MedianFinder) FindMedian() float64 { if h.MaxItem.Len() == h.MinItem.Len() { return float64(h.MaxItem.ReverseIntSlice[0]+h.MinItem.IntSlice[0]) / 2 } return float64(h.MaxItem.ReverseIntSlice[0]) }
下一篇:
C语言实现排序算法---希尔排序