LeetCode算法问题3 —— Median of Two Sorted Arrays

本文介绍了一种寻找两个已排序数组组合后的中位数的方法,通过遍历和比较两个数组元素来确定中位数的位置,避免了将数组合并排序带来的额外开销。

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

问题描述

这里写图片描述

问题要求我们找到给定的两个已排序的数组组合在一起的中位数(median)。

关于时间复杂度为O(log(m+n))的要求,我还没达到,但是想到了一个不错的方法,先记录下来。

说到中位数的计算,牵扯到这个数列的长度:

  • 为奇数:就取中间的数
  • 为偶数:取中间两位数的平均值

那么如何找到中位数呢?笨办法当然是乖乖地把两个数组的数都取出来然后排序,最后再取中位数。

但是我突然注意到了sorted,那么完全就不用把两个数组的数都放到一个新数组中做排序然后再取中位数。我的想法是分别给两个数组指针,然后依靠比大小来遍历(类似于排序),以数组[1,6],[2,3,5]为例详解:

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

挑选中位数自然就在这个排序中选取即可。

那么找到中位数之前我们需要知道什么呢:

  • ifLengthOdd(bool类型)判断这一系列数是否是奇数长度
  • medianPos(int类型)确定中心位置在哪
  • answer(double类型)作为问题的答案(先做加法——中间两位数相加,当然,这是在长度为偶数情况下;再做除法——偶数情况下除以2)

定义与获取自然就是这样的:

这里写图片描述

当然我们也要考虑给定的一个数组是空的情况下(vector类型存储)

这里写图片描述

排除空数组情况后,我们开始遍历,出于vector类型的考虑,且一开始是以指针来分析的,所以我打算用迭代器,但后来想想用下标访问或许更方便,因此对于两个数组,各需要一个pos1pos2来记录当前所指位置,还需要一个currentPos来表示我们当前是处在排序后总数组的哪一个位置,这样便于找到中位数,自然,找到中位数后,后面的排序我们并不关心。

我们首先以数组nums1作为参考,pos1何时才会向后移动呢?只有两种情况:

  1. nums1还有数没遍历完,且nums1当前所指的数小于nums2当前所指的数
  2. nums2已经遍历完了

否则就是pos2向后移动。当然,每次都相当于取出了一个数并排序,因此currentPos需要加1。

如果长度为奇数,median表示的就是中位数,如果长度为偶数,median表示的是其中两个数的第一个,至于下一个数我们在找到第一个数后再考虑,因此可以先把这个数传给answer,我写的循环遍历如图

这里写图片描述

最后再判断是否需要第二个数即可,这里nums1[pos1]nums2[pos2]还要再比较一次

这里写图片描述

这样就得到了中位数。

这个算法比较易于理解,好处是不用专门再开一个数组把这两个数组的数都传进去,节省了资源,也比较简便地完成了排序。缺点是我觉得这个算法始终算不上高明,时间复杂度也仅仅在O(n),达不到问题的要求,我将在最近继续思考,争取找出更优的算法。

下面是源代码:

double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    double answer = 0;
    bool ifLengthOdd = ((nums1.size() + nums2.size()) % 2 == 0) ? false : true;
            int medianPos = (nums1.size() + nums2.size()) / 2 + (ifLengthOdd ? 1 : 0);

    if (nums1.empty()) {
        if (ifLengthOdd)
            return nums2[medianPos - 1];
        else
            return (nums2[medianPos - 1] + nums2[medianPos]) / 2.0;
        }

    if (nums2.empty()) {
        if (ifLengthOdd)
            return nums1[medianPos - 1];
        else
            return (nums1[medianPos - 1] + nums1[medianPos]) / 2.0;
    }

    int pos1 = 0, pos2 = 0;
    int currentPos = 1;

/* 本层循环只找出中间那个数,长度奇偶问题循环完成后考虑 */ 
    while(1) {
        if ((nums1[pos1] <= nums2[pos2] && pos1 < nums1.size())
            || pos2 >= nums2.size()) {
            answer = nums1[pos1];
            pos1++;
        } else {
            answer = nums2[pos2];
            pos2++;
        }

        if (currentPos == medianPos)
            break;

        currentPos++;
    }

    if (!ifLengthOdd) {
        if ((nums1[pos1] <= nums2[pos2] && pos1 < nums1.size())
            || pos2 >= nums2.size())
            answer = (answer + nums1[pos1]) / 2.0;
        else
            answer = (answer + nums2[pos2]) / 2,0;
    }

    return answer;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值