【算法刷题】-中位数(数组、数据流)

微信搜索:编程笔记本。获取更多干货!
微信搜索:编程笔记本。获取更多干货!

点击上方蓝字关注我,我们一起学编程
欢迎小伙伴们分享、转载、私信、赞赏

中位数


中位数是有序数据中间位置的数。当数据总数为奇数时,中位数就是中间位置的一个数;当数据总数为偶数时,中位数就是中间两个相邻位置的平均值。

1 寻找两个有序数组的中位数

微信搜索:编程笔记本。获取更多干货!
微信搜索:编程笔记本。获取更多干货!

题目描述:

给定两个递增排序的数组,长度分别为 m 和 n ,要求找出这两个数组的中位数。

1.1 合并数据法

由于这两组数据不在同一个集合内,因此给我们寻找中位数带来了一定的困难。一个最直观的想法就是,将数据合并到同一个数据集中,然后直接找出中间位置的数据即可。下面是参考代码:

时间复杂度:O(m+n)
空间复杂度:O(m+n)

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        double ans;
        int idx1 = 0;        /* 数组1的元素的游标 */
        int idx2 = 0;        /* 数组2的元素的游标 */
        vector<int> nums;    /* 合并的数据集 */

        while (idx1 < nums1.size() && idx2 < nums2.size()) {
            if (nums1[idx1] < nums2[idx2]) {
                nums.push_back(nums1[idx1++]);
            } else {
                nums.push_back(nums2[idx2++]);
            }
        }

        while (idx1 < nums1.size()) {
            nums.push_back(nums1[idx1++]);
        }
        while (idx2 < nums2.size()) {
            nums.push_back(nums2[idx2++]);
        }

        if (nums.size() % 2 == 0) {
            int idx = nums.size() / 2;
            ans = (nums[idx - 1] + nums[idx]) / 2.0;
        } else {
            int idx = nums.size() / 2;
            ans = nums[idx];
        }

        return ans;
    }
};
1.2 二分查找法

上面的解法显然不是最优的解法,因为我们没有使用到“数组有序”这个条件。我们有一个直觉,这两个数组本来就是有序的,那么我们可不可以在 log 时间内求解问题呢?于是,我们想到了二分查找:在两个数组中寻找出较小的若干个数据,即可找到中间位置的数据。

时间复杂度:O(log(m+n))
空间复杂度:O(1)

微信搜索:编程笔记本。获取更多干货!
微信搜索:编程笔记本。获取更多干货!

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        double ans;
        int totalLength = nums1.size() + nums2.size();
        
        if (totalLength % 2 == 1) {
            ans = getKthElement(nums1, nums2, (totalLength + 1) / 2);
        } else {
            ans = (getKthElement(nums1, nums2, totalLength / 2) + getKthElement(nums1, nums2, totalLength / 2 + 1)) / 2.0;
        }
        
        return ans;
    }
    
    int getKthElement(const vector<int>& nums1, const vector<int>& nums2, int k) {
        int ans;
        int m = nums1.size();
        int n = nums2.size();
        int index1 = 0;
        int index2 = 0;

        while (true) {
            /* 边界情况 */
            if (index1 == m) {                   /* 中位数在数组2中 */
                return nums2[index2 + k - 1];
            }
            if (index2 == n) {                   /* 中位数在数组1中 */
                return nums1[index1 + k - 1];
            }
            if (k == 1) {
                ans = min(nums1[index1], nums2[index2]);
                break;
            }

            /* 正常情况 */
            int newIndex1 = min(index1 + k / 2 - 1, m - 1);
            int newIndex2 = min(index2 + k / 2 - 1, n - 1);
            int pivot1 = nums1[newIndex1];
            int pivot2 = nums2[newIndex2];
            
            if (pivot1 <= pivot2) {
                k -= newIndex1 - index1 + 1;
                index1 = newIndex1 + 1;
            } else {
                k -= newIndex2 - index2 + 1;
                index2 = newIndex2 + 1;
            }
        }
        
        return ans;
    }
};

微信搜索:编程笔记本。获取更多干货!
微信搜索:编程笔记本。获取更多干货!

2. 寻找数据流中的中位数

由于数据流中的数据总量不能确定,所以我们只能将已从数据流中获取的数据存入某种数据结构中,然后在取中位数时从数据结构中取。在这里,我们使用这种数据结构。

class MedianFinder { /***/
public:
    double findMedian() {
        if ((min.size() + max.size()) % 2 == 0) {
            return (min[0] + max[0]) / 2.0;
        } else {
            return min[0];
        }
    }

    void addNum(int num) {
        // 总数据数为偶数时将num插入到小根堆
        if ((min.size() + max.size()) % 2 == 0) {
            if (max.size() > 0 && num < max[0]) {
                max.push_back(num);
                push_heap(max.begin(), max.end(), less<int>());
                num = max[0];
                pop_heap(max.begin(), max.end(), less<int>());
                max.pop_back();
            }

            min.push_back(num);
            push_heap(min.begin(), min.end(), greater<int>());
        } else { // 总数据数为奇数时将num插入到大根堆
            if (min.size() > 0 && num > min[0]) {
                min.push_back(num);
                push_heap(min.begin(), min.end(), greater<int>());
                num = min[0];
                pop_heap(min.begin(), min.end(), greater<int>());
                min.pop_back();
            }

            max.push_back(num);
            push_heap(max.begin(), max.end(), less<int>());
        }
    }

private:
    vector<int> min;
    vector<int> max;
};

微信搜索:编程笔记本。获取更多干货!
微信搜索:编程笔记本。获取更多干货!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本系统的研发具有重大的意义,在安全性方面,用户使用浏览器访问网站时,采用注册和密码等相关的保护措施,提高系统的可靠性,维护用户的个人信息和财产的安全。在方便性方面,促进了校园失物招领网站的信息化建设,极大的方便了相关的工作人员对校园失物招领网站信息进行管理。 本系统主要通过使用Java语言编码设计系统功能,MySQL数据库管理数据,AJAX技术设计简洁的、友好的网址页面,然后在IDEA开发平台中,编写相关的Java代码文件,接着通过连接语言完成与数据库的搭建工作,再通过平台提供的Tomcat插件完成信息的交互,最后在浏览器中打开系统网址便可使用本系统。本系统的使用角色可以被分为用户和管理员,用户具有注册、查看信息、留言信息等功能,管理员具有修改用户信息,发布寻物启事等功能。 管理员可以选择任一浏览器打开网址,输入信息无误后,以管理员的身份行使相关的管理权限。管理员可以通过选择失物招领管理,管理相关的失物招领信息记录,比如进行查看失物招领信息标题,修改失物招领信息来源等操作。管理员可以通过选择公告管理,管理相关的公告信息记录,比如进行查看公告详情,删除错误的公告信息,发布公告等操作。管理员可以通过选择公告类型管理,管理相关的公告类型信息,比如查看所有公告类型,删除无用公告类型,修改公告类型,添加公告类型等操作。寻物启事管理页面,此页面提供给管理员的功能有:新增寻物启事,修改寻物启事,删除寻物启事。物品类型管理页面,此页面提供给管理员的功能有:新增物品类型,修改物品类型,删除物品类型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值