当前位置: 首页 > article >正文

[LeetCode] 295. 数据流的中位数

题目描述;

中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。

  • 例如 arr = [2,3,4] 的中位数是 3 。
  • 例如 arr = [2,3] 的中位数是 (2 + 3) / 2 = 2.5 。

实现 MedianFinder 类:

  • MedianFinder() 初始化 MedianFinder 对象。

  • void addNum(int num) 将数据流中的整数 num 添加到数据结构中。

  • double findMedian() 返回到目前为止所有元素的中位数。与实际答案相差 10-5 以内的答案将被接受。

示例 1:

输入
["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"]
[[], [1], [2], [], [3], []]
输出
[null, null, null, 1.5, null, 2.0]

解释
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1);    // arr = [1]
medianFinder.addNum(2);    // arr = [1, 2]
medianFinder.findMedian(); // 返回 1.5 ((1 + 2) / 2)
medianFinder.addNum(3);    // arr[1, 2, 3]
medianFinder.findMedian(); // return 2.0

提示:

  • -105 <= num <= 105
  • 在调用 findMedian 之前,数据结构中至少有一个元素
  • 最多 5 * 104 次调用 addNum 和 findMedian

题目链接:

. - 力扣(LeetCode)

解题主要思路:

如果直接硬解的话,即用vector<int>来存储,用快排来排序(nlogn)的话,时间复杂度肯定会超了的。

如果我们在插入vector<int>时像玩卡牌一样使用插入排序(n)的话,大概率也是会超时,可能addnum会调用5*104次;

因此,我们可以使用两个堆(logn),第一个堆采用大堆的方式,存的是数组左边的数,第二个堆采用小堆的方式,存的是数组右边的数。再插入的时候,严格控制left的大小要么和right的大小相同,要么比right的大小多一,这样我们就能在高效插入数据的同时,也能以O(1)的时间拿到中位数。

解题代码:

class MedianFinder {
    // 左边建大根堆
    priority_queue<int, vector<int>> left;
    // 右边建小根堆
    priority_queue<int, vector<int>, greater<int>> right;
public:
    MedianFinder() {

    }
    
    void addNum(int num) {
        // left_size == right_size
        if (left.size() == right.size()) {
            if (left.empty() || num <= left.top()) {
                left.push(num);
            }
            else {  // num > left.top()
                // 先放入right中,再将最right.top()放入左侧
                right.push(num);
                left.push(right.top());
                right.pop(); 
            }
        }
        else { // left_size + 1 == right_size
            if (num <= left.top()) {
                // 先放入左侧,再将left.top()放入右侧
                left.push(num);
                right.push(left.top());
                left.pop();
            }
            else {
                // num > left.top(); 直接放入right中
                right.push(num);
            }
        }
    }
    
    double findMedian() {
        if (left.size() == right.size()) return (left.top() + right.top())/2.0;
        else return left.top();
    }
};

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder* obj = new MedianFinder();
 * obj->addNum(num);
 * double param_2 = obj->findMedian();
 */


http://www.kler.cn/a/349348.html

相关文章:

  • 大厂面试真题-CPU飙升问题怎么定位
  • 交通路口智能监测平台实现
  • 呼兰:从程序员到脱口秀演员的双面人生
  • [Linux#62][TCP] 首位长度:封装与分用 | 序号:可靠性原理 | 滑动窗口:流量控制
  • 图的应用——关键路径
  • 深度优先搜索 - 岛屿最大面积
  • linux线程 | 同步与互斥(上)
  • Linux:信号保存与处理
  • 无人机与卫星光伏踏勘,谁会引领未来?
  • UE5蓝图学习笔记玩家碰撞触发死亡加一秒黑屏
  • 游​卡​三​面​​牧​原​三​面​​商​汤​一​面​​W​X​G​一​面
  • Vue GridLayout 入门指南
  • FunASR离线文件转写服务开发指南-debian-10.13
  • SpringBoot构建的健康管理推荐引擎
  • Vue 2 和 Vue 3 的区别
  • 面试22222
  • js 实现斐波那契数列
  • 软考中级笔记
  • desmos和webgl绘制线条
  • el-table表格里面有一条横线