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 以内的答案将被接受。
示例 1:
输入
["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"]
[[], [1], [2], [], [3], []]
输出
[null, null, null, 1.5, null, 2.0]
解释
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1); // arr = [1]
medianFinder.addNum(2); // arr = [1, 2]
medianFinder.findMedian(); // 返回 1.5 ((1 + 2) / 2)
medianFinder.addNum(3); // arr[1, 2, 3]
medianFinder.findMedian(); // return 2.0
题解:排序
- 超出时间限制,时间复杂度O(nlogn),每次调用 findMedian 都需要排序,造成整体效率低下。
var MedianFinder = function() {
this.arr = []
};
/**
* @param {number} num
* @return {void}
*/
MedianFinder.prototype.addNum = function(num) {
this.arr.push(num)
};
/**
* @return {number}
*/
MedianFinder.prototype.findMedian = function() {
const n = this.arr.length
this.arr.sort((a, b) => a - b); // 确保数组是排序的
if(n%2==0) {//偶数
return (this.arr[n/2-1]+this.arr[n/2])/2
}
else{//奇数
return this.arr[Math.floor(n/2)]
}
};
法二、二分
- 时间复杂度O(n)
var MedianFinder = function() {
this.arr = []; // 初始化一个空数组
};
/**
* 添加数字到数组中
* @param {number} num - 要添加的数字
* @return {void}
*/
MedianFinder.prototype.addNum = function(num) {
// 使用二分查找插入元素,以保持数组的排序
let left = 0;
let right = this.arr.length;
while (left < right) {
const mid = Math.floor((left + right) / 2);
if (this.arr[mid] < num) {
left = mid + 1;
} else {
right = mid;
}
}
// 在找到的位置插入元素
this.arr.splice(left, 0, num);
};
/**
* 查找当前数组的中位数
* @return {number} - 中位数
*/
MedianFinder.prototype.findMedian = function() {
const n = this.arr.length; // 获取数组长度
if (n % 2 === 0) { // 如果长度为偶数
return (this.arr[n / 2 - 1] + this.arr[n / 2]) / 2; // 返回中间两个数的平均值
} else { // 如果长度为奇数
return this.arr[Math.floor(n / 2)]; // 返回中间的数
}
};
法三、最大堆和最小堆
- 时间复杂度O(log n)
var MedianFinder = function() {
this.maxHeap = []; // 最大堆(存储较小的一半)
this.minHeap = []; // 最小堆(存储较大的一半)
};
/**
* 添加数字到堆中
* @param {number} num - 要添加的数字
* @return {void}
*/
MedianFinder.prototype.addNum = function(num) {
// 将数字添加到最大堆
this.maxHeap.push(num);
this.maxHeap.sort((a, b) => b - a); // 最大堆需要降序排列
// 确保最大堆的最大元素小于或等于最小堆的最小元素
if (this.minHeap.length > 0 && this.maxHeap[0] > this.minHeap[0]) {
const maxToMin = this.maxHeap.shift(); // 从最大堆移除最大元素
this.minHeap.push(maxToMin);
this.minHeap.sort((a, b) => a - b); // 最小堆需要升序排列
}
// 重新平衡堆的大小
if (this.maxHeap.length > this.minHeap.length + 1) {
const moveToMin = this.maxHeap.shift();
this.minHeap.push(moveToMin);
this.minHeap.sort((a, b) => a - b);
} else if (this.minHeap.length > this.maxHeap.length) {
const moveToMax = this.minHeap.shift();
this.maxHeap.push(moveToMax);
this.maxHeap.sort((a, b) => b - a);
}
};
/**
* 查找当前数组的中位数
* @return {number} - 中位数
*/
MedianFinder.prototype.findMedian = function() {
if (this.maxHeap.length > this.minHeap.length) {
return this.maxHeap[0]; // 最大堆的顶端是中位数
} else {
return (this.maxHeap[0] + this.minHeap[0]) / 2; // 两个堆的顶端的平均值
}
};
浙公网安备 33010602011771号