数据结构问题集锦 - Find Median from Data Stream
临近期末,鸭梨山大啊,就不多说了。这道题的要求就是,给定一串输入,在中间任何一个时候,都能够求出添加到一半的序列的中位数。
大概考虑一下,如果用动态数组来进行元素插入的话,尽管这样查询中位数的复杂度为O(1),由于每一次插入都是O(n),因而总复杂度为O(n^2),显然遭不住。如果用链表的话,插入单次还是O(n),而且求中位数反而更不是O(1)了,也不行。这时候注意到我们需要一个有序的序列来求中位数,所以可以建两个set,分别存放左半和右半序列,由于set本身数据是有序的,这样很容易就能查找到中位数了。
于是就可以写出如下代码:
1 template <typename T> 2 T last(set<T> _set) 3 { 4 return *(_set.rbegin()); 5 } 6 7 template <typename T> 8 T first(set<T> _set) 9 { 10 return *(_set.begin()); 11 } 12 13 class MedianFinder { 14 private: 15 set<int> left, right; 16 public: 17 //Adds a number into the data structure. 18 void addNum(int num) { 19 //Add new number first 20 if (left.empty()||(num<=last(left))) 21 left.insert(num); 22 else 23 right.insert(num); 24 25 //Arrange left and right queue 26 if (left.size()>=right.size()+2) 27 { 28 right.insert(last(left)); 29 left.erase(last(left)); 30 } 31 else if (left.size()<right.size()) 32 { 33 left.insert(first(right)); 34 right.erase(first(right)); 35 } 36 } 37 38 //Returns the median of current data stream 39 double findMedian() { 40 if (left.size()==right.size()) 41 return (last(left)+first(right))/2; 42 else 43 return last(left); 44 } 45 };
大家都知道C++中set是用红黑树实现的,于是每一次addNum都应该是O(log n)复杂度,findMedian函数写的其实不够好,因为每次添加过后其实都可以记录下当前的中位数,避免到set中去查找最后一项(现在复杂度是O(log n),如此重新设计之后能变成O(1))
不过悲催的是Leetcode还是Time Limit Exceeded了,果然我是算法渣啊...