思路一: 使用list作为数据结构。虽然accepted,但是效率很低,不建议。但这也是我唯一一个想到的数据结构,下面给出代码:
class MedianFinder {
List<Integer> list;
/** initialize your data structure here. */
public MedianFinder() {
list = new ArrayList<>();
}
public void addNum(int num) {
list.add(num);
}
public double findMedian() {
double res = 0;
Collections.sort(list);
int medIdx = list.size() / 2;
if(list.size() % 2 == 0){
res = (double)(list.get(medIdx - 1) + list.get(medIdx)) / 2;
}else{
res = (double)list.get(medIdx);
}
return res;
}
}
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.addNum(num);
* double param_2 = obj.findMedian();
*/
思路二: 使用heap作为数据结构,初始化两个堆,一个最大堆,一个最小堆。然后两个堆顶元素就可以决定median number。这个方法我没想到,其实就是不熟悉heap这个数据结构。堆是一个完全二叉树,因此堆操作效率也是相当的高。堆里面比较常用的就是最大堆和最小堆。这题正好两个都用到。这个算法核心思想就是把数组的数分为两半,用堆来存储,一半全是小的数,另一半全是大的数。其实就是相当于把数组先从小到大排序好了,然后中间切一刀,前面一半放进最大堆,后面一半放进最小堆。然后两个堆的顶部元素就决定了median number。下面直接给出代码:
class MedianFinder {
PriorityQueue< Integer > lo; //最大堆
PriorityQueue<Integer> hi; //最小堆
/** initialize your data structure here. */
public MedianFinder() {
lo = new PriorityQueue <> ();
hi = new PriorityQueue<>(Comparator.reverseOrder());
}
public void addNum(int num) {
lo.offer(num);
hi.offer(lo.poll());
if(lo.size() < hi.size()){
lo.offer(hi.poll());
}
}
public double findMedian() {
return lo.size() == hi.size() ? (double)((lo.peek() + hi.peek())/2.0) : (double)lo.peek();
}
}
/**
1. Your MedianFinder object will be instantiated and called as such:
2. MedianFinder obj = new MedianFinder();
3. obj.addNum(num);
4. double param_2 = obj.findMedian();
*/
总结:
- 熟悉heap数据结构
- 在java中priorityQueue 可以用作为heap。其中的add和offer方法可以理解为是相等的。peek和poll方法都是取堆顶元素,唯一的区别就是poll会删除堆顶元素,但是peek不会。