【LeetCode】剑指 Offer 41. 数据流中的中位数 p214 -- Java Version

这篇具有很好参考价值的文章主要介绍了【LeetCode】剑指 Offer 41. 数据流中的中位数 p214 -- Java Version。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目链接:https://leetcode.cn/problems/shu-ju-liu-zhong-de-zhong-wei-shu-lcof

1. 题目介绍(41. 数据流中的中位数)

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

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

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

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

【测试用例】:
示例 1:

输入
[“MedianFinder”,“addNum”,“addNum”,“findMedian”,“addNum”,“findMedian”]
[[],[1],[2],[],[3],[]]
输出:[null,null,null,1.50000,null,2.00000]

示例 2:

输入
[“MedianFinder”,“addNum”,“findMedian”,“addNum”,“findMedian”]
[[],[2],[],[3],[]]
输出:[null,null,2.00000,null,2.50000]

【条件约束】:

限制

  • 最多会对 addNum、findMedian 进行 50000 次调用。

【相关题目】:

注意:本题与主站 295. 数据流的中位数 题目相同。

2. 题解

2.1 最大堆和最小堆(原书题解) – O(logn)

时间复杂度O(logn),空间复杂度O(n)
偶数情况:
【LeetCode】剑指 Offer 41. 数据流中的中位数 p214 -- Java Version

解题思路】:
该题的解法很多,可以通过数组、链表、二叉搜索树、AVL树、最大堆和最小堆来实现,目前最推荐的就是使用 最大堆和最小堆 来解决该问题。该题可以将整个数据容器分成两部分,左边部分的数据要比右边的数据小。我们可以用一个最大堆实现左边的数据容器,用一个最小堆实现右边的数据容器。
两个保证

  1. 要保证数据平均分配到两个堆中,两个堆中数据的数目之差不能超过1;
  2. 要保证最小堆中的所有数据都要大于最大堆中的数据

……
实现策略】:

  1. 使用优先队列 PriorityQueue 实现最大堆和最小堆,优先队列的底层实现是一个最小堆,通过重写比较器的方法,可以将其改为大根堆;
    更多内容可参考:堆的实现(Java)
  2. 分配数据的插入位置,如果数据的总数目是 偶数,则把新数据插入到 小根堆,否则则插入到 大根堆
  3. 保证堆中数据正确,即小根堆中所有数据都要大于大根堆中的数据,因此就要进行判断,如果出现了要插入小根堆中的数据小于大根堆中的数据的情况,那么则将该数据插入到大根堆,并将大根堆的队首元素(最大值)弹出插入到小根堆中;
  4. 返回中点时进行判断,如果总数是偶数,则返回中点两数的平均值,如果是奇数,则返回小根堆的最小值。

……
注意点】:

  1. == 运算符的优先级要大于 & 运算符:
    【LeetCode】剑指 Offer 41. 数据流中的中位数 p214 -- Java Version
    因此,在判断总数目是偶数时要注意加上括号:((minHeap.size() + maxHeap.size()) & 1) == 0,挺麻烦的就是说,但如果你不加括号,就会出现下列问题:
    【LeetCode】剑指 Offer 41. 数据流中的中位数 p214 -- Java Version
    更多内容可参考:Java运算符优先级
class MedianFinder {
    
    // 最小堆 
    PriorityQueue<Integer> minHeap;
    
    // 最大堆
    PriorityQueue<Integer> maxHeap;

    /** initialize your data structure here. */
    public MedianFinder() {
        minHeap = new PriorityQueue<>();
        maxHeap = new PriorityQueue<>((i1, i2) -> Integer.compare(i2, i1));
    }
    
    public void addNum(int num) {

        // 如果总数目是偶数,则将数据存到小根堆
        if (((minHeap.size() + maxHeap.size()) & 1) == 0){
            if (maxHeap.size() > 0 && num < maxHeap.peek()){
                maxHeap.offer(num);
                minHeap.offer(maxHeap.poll());
            }else minHeap.offer(num);
        } else{ // 否则存到大根堆
            if (minHeap.size() > 0 && minHeap.peek() < num){
                minHeap.offer(num); 
                maxHeap.offer(minHeap.poll()); 
            }else maxHeap.offer(num);
        }
    }
    
    public double findMedian() {
        // 总数是偶数,返回两数平均值
        if (((minHeap.size() + maxHeap.size()) & 1) == 0){
            return (double)(minHeap.peek() + maxHeap.peek())/2;
        }else{ // 奇数,返回小根堆
            return minHeap.peek();
        }
    }
}

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

【LeetCode】剑指 Offer 41. 数据流中的中位数 p214 -- Java Version
代码简化:

简化思路】:
思路与上面差不多,只不过是简化省略了一些判断过程,直接将判断的过程扔给了堆,如:我要向大根堆插入一个数据,那么我就先要插入的数据扔到小根堆中,然后我把小根堆中最小的数插入大根堆,反之亦然,这样始终能保持小根堆存储较大一半、大根堆存储较小一半。
【LeetCode】剑指 Offer 41. 数据流中的中位数 p214 -- Java Version

class MedianFinder {
    Queue<Integer> A, B;
    public MedianFinder() {
        A = new PriorityQueue<>(); // 小顶堆,保存较大的一半
        B = new PriorityQueue<>((x, y) -> (y - x)); // 大顶堆,保存较小的一半
    }
    public void addNum(int num) {
        if(A.size() != B.size()) {
            A.add(num);
            B.add(A.poll());
        } else {
            B.add(num);
            A.add(B.poll());
        }
    }
    public double findMedian() {
        return A.size() != B.size() ? A.peek() : (A.peek() + B.peek()) / 2.0;
    }
}

【LeetCode】剑指 Offer 41. 数据流中的中位数 p214 -- Java Version

3. 参考资料

[1] 面试题41. 数据流中的中位数(优先队列 / 堆,清晰图解)文章来源地址https://www.toymoban.com/news/detail-403547.html

到了这里,关于【LeetCode】剑指 Offer 41. 数据流中的中位数 p214 -- Java Version的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 软件定义汽车场景中的数据流处理

    在当今快速发展的技术环境中,汽车行业正处于变革期。软件定义汽车(Software-Defined Vehicle, SDV)处于这场变革的前沿,为用户提供了无与伦比的互联、智能和数据洞察。SDV 会产生海量的数据,如何实时高效的处理这些数据成为当务之急。 本文将深入分析 SDV 数据的流处理技

    2024年02月13日
    浏览(31)
  • 数据流处理中的分布式存储:保护数据隐私和安全

    作者:禅与计算机程序设计艺术 随着数据量的爆炸式增长,如何高效地处理和存储数据成为了当前热门的研究方向。数据流处理作为一种处理数据的方法,能够在实时性、流式性和可扩展性等方面提供优势。在数据流处理中,分布式存储是保障数据隐私和安全的重要手段。本

    2024年02月16日
    浏览(25)
  • (搜索) 剑指 Offer 12. 矩阵中的路径 ——【Leetcode每日一题】

    难度:中等 给定一个 m * n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许

    2024年02月12日
    浏览(32)
  • leetcode(力扣) 剑指 Offer 12. 矩阵中的路径(回溯 DFS)

    给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

    2024年02月14日
    浏览(34)
  • (排序) 剑指 Offer 51. 数组中的逆序对 ——【Leetcode每日一题】

    难度:困难 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。 示例 1: 输入: [7,5,6,4] 输出: 5 限制 : 0 = 数组长度 = 50000 💡思路:归并排序 预备知识 「 归并排序 」是用 分治 思想,分

    2024年02月11日
    浏览(34)
  • 剑指 Offer 12. 矩阵中的路径 / LeetCode 79. 单词搜索(深度优先搜索)

    链接:剑指 Offer 12. 矩阵中的路径;LeetCode 79. 单词搜索 难度:中等 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相

    2024年02月02日
    浏览(29)
  • 替换空格&&反转字符串中的单词(LeetCode 剑指offer05 && 151)

    题目 剑指 Offer 05. 替换空格  思路 遍历,使用新的字符串来接原字符串,如为空格,则加入%20,否则加入原字符串。  不过看了题解有另一种解法,由于空格转化为%20,设计到原字符存储空间的增加,因此先计算出需要增加的空间后。再使用双指针,从后往前遍历,这里画的

    2024年02月16日
    浏览(31)
  • 什么是Vue的数据流(单向数据流)?如何进行数据流管理

    在Vue中,数据流是指数据的传递和管理方式。Vue采用的是单向数据流,也就是说,数据是从父组件流向子组件,子组件不能直接修改父组件的数据。本文将介绍Vue的数据流机制,以及如何进行数据流管理。 Vue的数据流机制可以分为两类:props和events。 Props 在Vue中,父组件可以

    2024年02月08日
    浏览(43)
  • 银行储蓄系统的顶层数据流图及细化数据流图

    绘制出银行储蓄系统的顶层数据流图及细化数据流图; 银行储蓄系统存、取款流程如下: 1)业务员事先录入利率信息; 2)如果是存款,储户填写存款单,业务员将存款单键入系统,系统更新储户存款信息(存款人姓名、存款人账号、电话号码、身份证号码、存款金额、存

    2024年01月17日
    浏览(36)
  • Elasticsearch:将 ILM 管理的数据流迁移到数据流生命周期

    警告 :此功能处于技术预览阶段,可能会在未来版本中更改或删除。 Elastic 将努力解决任何问题,但技术预览版中的功能不受官方 GA 功能的支持 SLA 的约束。目前的最新版本为 8.12。 在本教程中,我们将了解如何将现有数据流(data stream)从索引生命周期管理 (ILM) 迁移到数据

    2024年04月29日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包