数据结构问题集锦

临近期末,鸭梨山大啊,就不多说了。这道题的要求就是,给定一串输入,在中间任何一个时候,都能够求出添加到一半的序列的中位数。

大概考虑一下,如果用动态数组来进行元素插入的话,尽管这样查询中位数的复杂度为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了,果然我是算法渣啊...

原文地址:https://www.cnblogs.com/lqf-96/p/find-median-from-data-stream.html