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])
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ostrich5yw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值