1.题目描述
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例:addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2
进阶:如果数据流中所有整数都在 0 到 100 范围内,你将如何优化你的算法?
如果数据流中 99% 的整数都在 0 到 100 范围内,你将如何优化你的算法?
2.解题思路
进阶一:数据流中所有整数都在 0 到 100 范围内
用一个数组保存每个数字出现的次数。
时间复杂度和空间复杂度均是O(1)。
JAVA代码:
public class MedianFinder {
int[] count;
int total;
/** initialize your data structure here. */
public MedianFinder() {
count = new int[101];
total = 0;
}
public void addNum(int num) {
count[num]++;
total++;
}
public double findMedian() {
if (0 == total % 2) {
return (findKthNumber(total / 2) + findKthNumber(total / 2 + 1)) / 2.0;
} else {
return findKthNumber(total / 2 + 1);
}
}
private int findKthNumber(int k) {
int index = 0;
for (int i = 0; i < 101; i++) {
index += count[i];
if (index >= k) {
return i;
}
}
return -1;
}
}
进阶二:数据流中 99% 的整数都在 0 到 100 范围内
和进阶一同样的思路,只不过将大于100的数除去即可,因为有99%的整数都在0到100范围内,所以中位数一定是0到100范围内的某个数,只需根据大于100的数的个数在进阶一的基础上调整即可。
时间复杂度和空间复杂度均是O(1)。
public class MedianFinder {
int[] count;
int total;
int greaterThan100;
/** initialize your data structure here. */
public MedianFinder() {
count = new int[101];
total = 0;
greaterThan100 = 0;
}
public void addNum(int num) {
if (num <= 100) {
count[num]++;
} else {
greaterThan100++;
}
total++;
}
public double findMedian() {
int temp = total - greaterThan100 * 2;
if (0 == temp % 2) {
return (findKthNumber(greaterThan100 + temp / 2) + findKthNumber(greaterThan100 + temp / 2 + 1)) / 2.0;
} else {
return findKthNumber(greaterThan100 + temp / 2 + 1);
}
}
private int findKthNumber(int k) {
int index = 0;
for (int i = 0; i < 101; i++) {
index += count[i];
if (index >= k) {
return i;
}
}
return -1;
}
}
参考:https://blog.csdn.net/qq_41231926/article/details/90576809#comments
3.代码实现
class MedianFinder(object):
def __init__(self):
"""
initialize your data structure here.
"""
self.maxheap=[]
self.minheap=[]
def addNum(self, num):
"""
:type num: int
:rtype: None
"""
# 数字来了就往大根堆里插入
heapq.heappush(self.maxheap,-num)
# 如果逆序就交换
if len(self.minheap)>0 and self.minheap[0] < -self.maxheap[0]:
t1=heapq.heappop(self.minheap)
t2=-heapq.heappop(self.maxheap)
heapq.heappush(self.minheap,t2)
#把小的取出来,重新放入大根堆,还是要取负
heapq.heappush(self.maxheap,-t1)
# 如果下多就转移
if len(self.maxheap)-len(self.minheap)>1:
t2=-heapq.heappop(self.maxheap)
heapq.heappush(self.minheap,t2)
def findMedian(self):
"""
:rtype: float
"""
if (len(self.maxheap)+len(self.minheap))%2==0:
return (self.minheap[0]+(-self.maxheap[0]))/2.0
else:
return -self.maxheap[0]
# Your MedianFinder object will be instantiated and called as such:
# obj = MedianFinder()
# obj.addNum(num)
# param_2 = obj.findMedian()