这道题在力扣官网上面是困难难度。但是假如利用好 C++ 的优先队列或者利用好大根堆和小根堆,这道题的思路其实很简单。
题目描述:
题号:295
中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。
-
例如
arr = [2,3,4]
的中位数是3
。 -
例如
arr = [2,3]
的中位数是(2 + 3) / 2 = 2.5
。
实现 MedianFinder 类:
-
MedianFinder()
初始化MedianFinder
对象。 -
void addNum(int num)
将数据流中的整数num
添加到数据结构中。 -
double findMedian()
返回到目前为止所有元素的中位数。与实际答案相差10-5
以内的答案将被接受。
解题思路:
思路一:优先队列
初始化两个空堆:一个最大堆(maxHeap
)和一个最小堆(minHeap
)。
-
将新数字与
maxHeap
的堆顶(即较小一半的最大值)进行比较。 -
如果新数字小于等于
maxHeap
的堆顶,则将其添加到maxHeap
中。此时,我们需要检查两个堆的大小关系,确保maxHeap
的大小始终小于等于minHeap
的大小,或相差1。如果maxHeap
的大小超过了minHeap
的大小加1,我们需要将maxHeap
的堆顶元素移除,并添加到minHeap
中。 -
否则,将新数字的负值添加到
minHeap
中。同样,我们需要检查两个堆的大小关系。如果minHeap
的大小超过了maxHeap
的大小,我们需要将minHeap
的堆顶元素(取负后)移除,并添加到maxHeap
中。
如果两个堆的大小不一样,则中位数为 maxHeap 的堆顶。
否则,中位数为 maxHeap 堆顶和 minHeap 堆顶的值相加除以 2。
时间复杂度:O(log N)
空间复杂度:O(N)
C++
cpp
// C++
class MedianFinder {
priority_queue<int> bigHeap; // small part, extra one
priority_queue<int, vector<int>, greater<int>> smallHeap; // big part
public:
MedianFinder() {
}
void addNum(int num) {
if(bigHeap.size() == smallHeap.size()) {
smallHeap.push(num);
bigHeap.push(smallHeap.top());
smallHeap.pop();
} else {
bigHeap.push(num);
smallHeap.push(bigHeap.top());
bigHeap.pop();
}
}
double findMedian() {
if(bigHeap.size() == smallHeap.size()) {
return (bigHeap.top() + smallHeap.top()) / 2.0;
}
return bigHeap.top();
}
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder* obj = new MedianFinder();
* obj->addNum(num);
* double param_2 = obj->findMedian();
*/
go
Go
// go
// 定义一个最大堆
type BigHeap []int
func (h BigHeap) Len() int { return len(h) }
func (h BigHeap) Less(i, j int) bool { return h[i] > h[j] }
func (h BigHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *BigHeap) Push(x interface{}) {
*h = append(*h, x.(int))
}
func (h *BigHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
// 定义一个最小堆
type SmallHeap []int
func (h SmallHeap) Len() int { return len(h) }
func (h SmallHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h SmallHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *SmallHeap) Push(x interface{}) {
*h = append(*h, x.(int))
}
func (h *SmallHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
type MedianFinder struct {
bigHeap BigHeap
smallHeap SmallHeap
}
func Constructor() MedianFinder {
return MedianFinder{
bigHeap: make(BigHeap, 0),
smallHeap: make(SmallHeap, 0),
}
}
func (this *MedianFinder) AddNum(num int) {
if len(this.bigHeap) == len(this.smallHeap) {
heap.Push(&this.smallHeap, num)
heap.Push(&this.bigHeap, heap.Pop(&this.smallHeap).(int))
} else {
heap.Push(&this.bigHeap, num)
heap.Push(&this.smallHeap, heap.Pop(&this.bigHeap).(int))
}
}
func (this *MedianFinder) FindMedian() float64 {
if len(this.bigHeap) == len(this.smallHeap) {
return float64(this.bigHeap[0]+this.smallHeap[0]) / 2.0
}
return float64(this.bigHeap[0])
}
/**
* Your MedianFinder object will be instantiated and called as such:
* obj := Constructor();
* obj.AddNum(num);
* param_2 := obj.FindMedian();
*/