• 力扣295.数据流的中位数[困难]


    中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。

    例如,

    [2,3,4] 的中位数是 3

    [2,3] 的中位数是 (2 + 3) / 2 = 2.5

    设计一个支持以下两种操作的数据结构:

    • void addNum(int num) - 从数据流中添加一个整数到数据结构中。
    • double findMedian() - 返回目前所有元素的中位数。
      1. addNum(1)
      2. addNum(2)
      3. findMedian() -> 1.5
      4. addNum(3)
      5. findMedian() -> 2

    解法一:堆实现(B大顶堆和S小顶堆分别存放小数、大数)

            分析:使用优先队列保持有序结构,设元素总数为 N = m + n ,其中 m 和 n 分别为 S和 B 中的元素个数。

    1. class MedianFinder {
    2. public:
    3. priority_queue<int,vector<int>,greater<int>> S;//小顶堆
    4. priority_queue<int,vector<int>,less<int>> B;//大顶堆
    5. MedianFinder() {}
    6. void addNum(int num) {
    7. if(S.size()!=B.size()){//左边大数多了
    8. S.push(num);
    9. B.push(S.top());
    10. S.pop();
    11. }
    12. else{
    13. B.push(num);
    14. S.push(B.top());
    15. B.pop();
    16. }
    17. }
    18. double findMedian() {
    19. return S.size()!=B.size()? S.top(): (S.top()+B.top())/2.0;
    20. }
    21. };

    解法二:有序队列+双指针

            我们把有序集合看作自动排序的数组,使用双指针指向有序集合中的中位数元素即可。当累计添加的数的数量为奇数时,双指针指向同一个元素。当累计添加的数的数量为偶数时,双指针分别指向构成中位数的两个数。

    1. class MedianFinder {
    2. public:
    3. MedianFinder() {left=nums.begin();right=nums.end();}
    4. void addNum(int num) {
    5. int len = nums.size();
    6. nums.insert(num);
    7. if(len<1){//数据为空
    8. left=right=nums.begin();
    9. }
    10. else if(len&1){//数据为奇数
    11. if(num<*left){
    12. left--;
    13. }
    14. else{
    15. right++;
    16. }
    17. }
    18. else{//数据为偶数,新添加的数字有三种情况,夹在原来偶数中间,分在左或者右
    19. // if(num<=*left){
    20. // right--;
    21. // //left=right;//这一步是针对,新插入值等于左侧的值,这时候这个值会插入到两个值的中间,set的重复值插入到原来数值的右边
    22. //可以使用 num<*left 在判断的时候将其归类为第三类中间值去处理
    23. // }
    24. if(num<*left){
    25. right--;
    26. }
    27. else if(num>=*right){
    28. left++;
    29. }
    30. else{
    31. left++;right--;
    32. }
    33. }
    34. }
    35. double findMedian() {
    36. return (*left+*right)/2.0;
    37. }
    38. private:
    39. multiset<int> nums;
    40. multiset<int> ::iterator left ,right;
    41. };

    解法三:存储时保持有序(超时)

    1. class MedianFinder {
    2. public:
    3. /** initialize your data structure here. */
    4. MedianFinder() {
    5. }
    6. void addNum(int num) {
    7. int i=0;
    8. //while (i<res.size() && res[i] < num) i++;
    9. for(i;i<res.size();i++){
    10. if(res[i]>=num){
    11. break;
    12. }
    13. }
    14. res.insert(res.begin()+i, num);
    15. }
    16. double findMedian() {
    17. if (res.empty()) return NULL;
    18. if (res.size() % 2) return res[res.size()/2];
    19. return (res[res.size()/2] + res[res.size()/2 -1] )/2.0;
    20. }
    21. private:
    22. vector<int> res;
    23. };

    解法四:私调用快速排序(超时)

    1. class MedianFinder {
    2. public:
    3. /** initialize your data structure here. */
    4. vector<double> res;
    5. MedianFinder() {}//默认构造
    6. void addNum(int num) {
    7. res.push_back(num);
    8. }
    9. double findMedian() {
    10. int len = res.size();
    11. if(len<1){
    12. return 0;
    13. }
    14. //sort(res.begin(),res.end());这个时间会超时
    15. quicksort(res,0,len-1);
    16. if(len%2==0){
    17. return (res[len/2]+res[len/2-1])/2;
    18. }
    19. else{
    20. return res[(len-1)/2];
    21. }
    22. }
    23. private:
    24. void quicksort(vector<double> &arr,int l,int r){
    25. if(l>r)return;
    26. int i=l,j=r;
    27. while(i<j){
    28. while(i<j&&arr[j]>=arr[l])j--;
    29. while(i<j&&arr[i]<=arr[l])i++;
    30. swap(arr[i],arr[j]);
    31. }
    32. swap(arr[i],arr[l]);
    33. quicksort(arr,l,i-1);
    34. quicksort(arr,i+1,r);
    35. }
    36. };

  • 相关阅读:
    SpringMVC 进阶
    基于Java+SpringBoot+vue+element疫情药品采购出入库系统设计实现
    JVM系列第二期——双亲委派和类加载器
    kubelets 1.20 证书更新
    元宇宙电商-NFG系统,是如何让数字藏品流通的?
    4. algorithm
    生成树协议:监控 STP 端口和交换机
    如何编写高质量和可维护的C++代码?
    websocket入门
    python:自动获取当前系统的路径(windows+linux)、xlsx文件转换为csv文件
  • 原文地址:https://blog.csdn.net/Dejan520/article/details/125570941