LeetCode 热题 100 | 堆(三)

本文介绍了如何使用C++实现数据流中位数问题,利用大根堆和小根堆维护队列,确保在不断添加数据时快速找到中位数。详细解释了解题思路、操作过程以及代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1  队列 - v2.0

2  295. 数据流的中位数

2.1  解题思路

2.2  举例说明

2.3  维持队列

2.4  求中位数

2.5  完整代码


菜鸟做题,语言是 C++

1  队列 - v2.0

排序规则果然和名字是反过来的:

// 大根堆
priority_queue<int, vector<int>, less<int>> queMin;
// 小根堆
priority_queue<int, vector<int>, greater<int>> queMax;

2  295. 数据流的中位数

2.1  解题思路

解题思路:

  • 维护两个优先队列 queMin 和 queMax
  • 前者(是大根堆)存放比中位数 midNum 小的数
  • 后者(是小根堆)存放比中位数 midNum 大的数

解题要点:

  • 维护 midNum 以进行比较
  • 保持 queMin 和 queMax 的大小基本一致

本质上就是将 nums 数组砍半,并且是按从小到大的顺序分别存储在 queMin 和 queMax 中的。到时候,中位数必定出自 queMin 或 queMax 的根元素。

2.2  举例说明

假设 nums 是 [4,5,2,1,3] 。

对于第一个数字 4,我们可以不分青红皂白地把它插入到 queMin 中,同时更新中位数为 4;对于第二个数字 5,由于 5 大于中位数,因此插入 queMax 中,同时更新中位数为 4.5;对于第三个数字 2,由于 2 小于中位数,因此插入 queMin 中。

对于第四个数字 1,由于 1 小于中位数,因此插入 queMin 中。注意:这个时候 queMin 比 queMax 多两个元素了,不满足 “砍半” 要求!因此我们需要将 4 转移到 queMax 中,同时更新中位数为 3。对于第五个数字 3,由于 3 等于中位数,因此随机插入 queMin 中。

2.3  维持队列

对 2.2 节思路的实现

void addNum(int num) {
    if (!queMin.size()) {
        queMin.push(num);
        return;
    }

    midNum = findMedian();
    if (num < midNum) {
        if (queMin.size() > queMax.size()) {
            queMax.push(queMin.top());
            queMin.pop();
        }
        queMin.push(num);
    } else {
        if (queMin.size() < queMax.size()) {
            queMin.push(queMax.top());
            queMax.pop();
        }
        queMax.push(num);
    }
}

2.4  求中位数

代码逻辑:

  • 若 queMin 和 queMax 不一样长,则中位数是较长一方的根元素
  • 若 queMin 和 queMax 一样长,则中位数等于二者根元素之和 / 2
double findMedian() {
    double ans;
    if (queMin.size() < queMax.size()) {
        ans = queMax.top();
    } else if (queMin.size() > queMax.size()) {
        ans = queMin.top();
    } else {
        ans = (queMin.top() + queMax.top()) / 2.0;
    }
    return ans;
}

2.5  完整代码
class MedianFinder {
private:
    priority_queue<int, vector<int>, less<int>> queMin;
    priority_queue<int, vector<int>, greater<int>> queMax;
    int midNum;

public:
    MedianFinder() { }
    
    void addNum(int num) {
        if (!queMin.size()) {
            queMin.push(num);
            return;
        }

        midNum = findMedian();
        if (num < midNum) {
            if (queMin.size() > queMax.size()) {
                queMax.push(queMin.top());
                queMin.pop();
            }
            queMin.push(num);
        } else {
            if (queMin.size() < queMax.size()) {
                queMin.push(queMax.top());
                queMax.pop();
            }
            queMax.push(num);
        }
    }
    
    double findMedian() {
        double ans;
        if (queMin.size() < queMax.size()) {
            ans = queMax.top();
        } else if (queMin.size() > queMax.size()) {
            ans = queMin.top();
        } else {
            ans = (queMin.top() + queMax.top()) / 2.0;
        }
        return ans;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值