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

2 篇文章 0 订阅
2 篇文章 0 订阅

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。

进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
示例 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
示例 3:

输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例 4:

输入:nums1 = [], nums2 = [1]
输出:1.00000
示例 5:

输入:nums1 = [2], nums2 = []
输出:2.00000
这题看了题解,作者:bian-bian-xiong,讲的很好,我来简要概述一下。
先说说中位数的作用是什么?在统计中,中位数被用来:将一个集合划分为两个长度相等的子集,其中一个子集中的元素总是大于另一个子集中的元素。
还有就是割(cut),割(cut)左右两边有两个元素,分别是左边最大值和右边最小值,分别定义为LMax和RMin,割可以割在两个数中间,也可以割在1个数上,如果割在一个数上,那么这个数即属于左边,也属于右边。那么,奇数组割在一个数上,偶数组割在两个数之间。
设:
Ci为第i个数组的割。
LMaxi为第i个数组割后的左元素。
RMini为第i个数组割后的右元素。
在这里插入图片描述
首先,LMax1<=RMin1,LMax2<=RMin2 这是肯定的,因为数组是有序的,左边肯定小于右边!,而如果割(Cut)在某个数上,则左右相等。
而我们需要让LMax1<=RMin2,LMax2<=RMin1。这样左边就全部小于右边。如果左边的元素个数相加刚好等于k, 那么第k个元素就是Max(LMax1, LMax2)。
如果LMax1>RMin2,那么C1需要减小,C2就相应的增加;如果LMax2>RMin1,那么C2需要减小,那么C1就相应的增加。
而这位作者最巧妙的地方就是让两个数组的长度m+n恒为偶数,通过虚拟加入‘#’,我们让m转换成2m+1 ,n转换成2n+1, 两数之和就变成了2m+2n+2,恒为偶数。
在这里插入图片描述
这样虚拟之后,每个元素位置/2之后可以得到本来的位置。
LMaxi = (Ci-1)/2 位置上的元素
RMini = Ci/2 位置上的元素
而Mid = (A[m+n+1]+A[m+n+2])/2 = (Max(LMax1,LMax2) + Min(RMin1,RMin2) )/2;
还有4种极端情况,如果有个数组完全小于或大于中值。假定n<m:
C1 = 0 —— 数组1整体都在右边了,所以都比中值大,中值在数组2中,简单的说就是数组1割后的左边是空了,所以我们可以假定LMax1 = INT_MIN
C1 =2n —— 数组1整体都在左边了,所以都比中值小,中值在数组2中 ,简单的说就是数组1割后的右边是空了,所以我们可以假定RMin1= INT_MAX,来保证LMax2<RMin1恒成立
C2 = 0 —— 数组2整体在右边了,所以都比中值大,中值在数组1中 ,简单的说就是数组2割后的左边是空了,所以我们可以假定LMax2 = INT_MIN
C2 = 2m —— 数组2整体在左边了,所以都比中值小,中值在数组1中, 简单的说就是数组2割后的右边是空了,为了让LMax1 < RMin2 恒成立,我们可以假定RMin2 = INT_MAX。
如果不是极端情况LMax1,RMin1,LMax2, RMin2 就正常变换,分别是lmax1=nums1[(c1-1)/2];rmin1=nums1[c1/2];lmax2=nums2[(c2-1)/2];rmin2=nums2[c2/2];
思考:这题求的是中位数,如果是求第k小的元素也能用此法做,我的想法是限制一下c1,c2的长度就行,使他们等于k,不知道这样做是不是时间复杂度较小的做法。

const int INF=99999999;
class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int n,m;
        n=nums1.size();
        m=nums2.size();
        if(n>m){
           return findMedianSortedArrays(nums2,nums1);
        }
        int lmax1,lmax2,rmin1,rmin2,l=0,r=2*n,c1,c2;
        while(l<=r)        //小于等于
        {
            c1=(l+r)/2;
            c2=m+n-c1;
            if(c1==0){
                lmax1=-INF;
            }
            else{
                lmax1=nums1[(c1-1)/2];
            }
            if(c1==2*n){
                rmin1=INF;
            }
            else{
                rmin1=nums1[c1/2];
            }
            if(c2==0){
                lmax2=-INF;
            }
            else{
                lmax2=nums2[(c2-1)/2];
            }
            if(c2==2*m){
                rmin2=INF;
            }
            else{
                rmin2=nums2[c2/2];
            }

            if(lmax1>rmin2){
                r=c1-1;
            }
            else if(lmax2>rmin1){
                l=c1+1;
            }
            else break;
        }
        return (max(lmax1,lmax2)+min(rmin1,rmin2))/2.0;

    }
};

``

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值