目录
- 题目
- 题解:排序
- 法二、二分
- 法三、最大堆和最小堆
题目
- 中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。
例如 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.lengththis.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; // 两个堆的顶端的平均值}
};