寻找两个正序数组的中位数

寻找两个正序数组的中位数

时隔许久,我又回来了。

题目:给定两个大小分别为m和n的正序(从小到大)数组nums1和nums2。请你找出并返回这两个正序数组的中位数
要求算法的时间复杂度为O(log(m+n))

示例1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

示例2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

题目链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/

C++实现

方法一:
很朴素的想法,通过归并排序的思路将两个正序数组合并为一个数组data,再根据data所含个数的奇偶性分别返回相应的结果。
时间复杂度O(m+n)

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        //新开辟数组data,记录nums1和nums2合并后的有序数组
        vector<int> data;
        int i=0,j=0;
        while(i<nums1.size()&&j<nums2.size())
        {
            if(nums1[i]<nums2[j]){
                data.push_back(nums1[i++]);
            }
            else{
                data.push_back(nums2[j++]);
            }
        }
        while(i<nums1.size())
        {
            data.push_back(nums1[i++]);
        }
        while(j<nums2.size())
        {
            data.push_back(nums2[j++]);
        }
        double ret=0; //待返回的中位数
        if(data.size()%2==1)
        {
            ret=data[data.size()/2];
        }
        else{
            ret=(data[(data.size()-1)/2]+data[(data.size()-1)/2+1])/2.0;
        }
        return ret;
    }
};

方法二:
借鉴官方题解,通过二分查找实现。时间复杂度O(log(m+n))
m+n是奇数时,中位数是两个正序数组中的第(m+n)/2+1个元素(从1开始数);
m+n是偶数时,中位数是两个正序数组中的第(m+n)/2和第(m+n)/2+1个元素的平均值。

因此主要问题是实现找到两个正序数组的第k个元素的函数findKth(),如下所示:
使用index1和index2分别记录删除部分元素后,num1和num2下标的偏移量。初始为0。
比较num1[k/2-1]和num2[k/2-1],以num1[k/2-1]<num2[k/2-1]为例,反之同理。num1[k/2-1]左侧共k/2-1个元素,即使num2[k/2-1]左侧的k/2-1个元素均全部小于num1[k/2-1]时,num1[k/2-1]名次取到最大为k-1,无法成为第k个元素。因此num1[k/2-1]及其左侧的元素均可排除,即nums1[0]到nums1[k/2-1]。k相应减少k/2个元素。
由于存在删除元素后考虑位置发生偏移,因此需要加上相应的基准index1和index2
要注意可能存在index*+k/2-1下标越界的情况:nextIndex1=min(index1+k/2-1,m-1)。如果某一个数组越界,直接返回另一个数组中的第k个元素。

示例分析:
num1={1,3,4,9}
num2={1,2,3,4,5,6,7,8,9}
找第k=(4+9)/2+1=7个元素
在这里插入图片描述
index1=0,index2=0,比较下标为k/2-1=2的两个数:num1[2]=4>num2[2]=3,于是num2[index2]到num2[index2+k/2-1]范围内的元素被排除。修改index2和k:index2=3,k=k-k/2=4。index1=0。
在这里插入图片描述
比较num1[index1+k/2-1]=num1[1]和num2[index2+k/2-1]=num2[4]:num1[1]=3<num2[4]=5。于是num1[0]到num1[1]范围元素被排除。修改index1和k:index1=2,k=k-k/2=2。index2=3。
在这里插入图片描述
比较num1[index1+k/2-1]=num1[2]和num2[index2+k/2-1]=num2[3]:num1[2]=4<num2[3]=4。于是num1[2]到num1[2]范围元素被排除。修改index1和k:index1=3,k=k-k/2=1。index2=3。
在这里插入图片描述
k==1时,返回num1[index1]和num2[index2]中较小的一个,结束循环。这里返回4即为所求第7个数。

代码:

class Solution {
public:
    int findKth(vector<int>& nums1, vector<int>& nums2,int k) //找到两个正序数组的第k个元素
    {
        int m=nums1.size();
        int n=nums2.size();
        int index1=0,index2=0; //index1和index2分别记录num1和num2各自的偏移量
        while(1)
        {
        	//边界情况
            if(index1==m){return nums2[index2+k-1];} //num1越界
            if(index2==n){return nums1[index1+k-1];} //num2越界
            if(k==1){return min(nums1[index1],nums2[index2]);}
            //正常情况
            int nextIndex1=min(index1+k/2-1,m-1); //下一个比较值下标,注意越界时删除元素变少
            int nextIndex2=min(index2+k/2-1,n-1);
            if(nums1[nextIndex1]<=nums2[nextIndex2])
            {
                k-=(nextIndex1-index1+1); //修改k
                index1=nextIndex1+1; //删除num1中元素,修改index1
            }
            else{
                k-=(nextIndex2-index2+1); //修改k
                index2=nextIndex2+1; //删除num2中元素,修改index2
            }
        }
    }
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m=nums1.size();
        int n=nums2.size();
        if((m+n)%2==1){return findKth(nums1,nums2,(m+n)/2+1);}
        else{return (findKth(nums1,nums2,(m+n)/2)+findKth(nums1,nums2,(m+n)/2+1))/2.0;}
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值