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

原题目:

  给定两个大小为m,n的有序数组nums1和nums2,找出这两个有序数组的中位数,要求时间复杂度为O(log(m+n)).

  eg:nums1=[1,3];nums2=[2];中位数是2.0

  nums1=[1,2];nums2=[3,4];中位数是(2+3)/2=2.5

不考虑时间复杂度,简单做法就是把nums1和nums2两个数组的并集重新排序,取得中位数。

基本思想:
需要求的中位数mid是把两个数组并集构成的数组num3的元素分为数目相等的两部分。设小于mid的元素构成集合C。
计算两个数组元素总长度sumLen
需要向C中添加的元素长度为(sumLen+1)/2 向下取整

   最开始仍需要添加到C中元素的长度为want=(sumLen+1)/2 向下取整,取索引值为indexa=indexb=want/2;

 

比较nums1[indexa]与nums2[indexb]的大小(谁数值大,谁索引二分),假设nums1[indexa]<nums2[indexb],就对nums2再次进行二分找元素,直到nums1[indexa]>nums2[indexb],

假设indexb连续二分两次过后(indexb=indexb/2),nums1[indexa]>nums2[indexb],

      然后把nums1索引z为indexa和indexa之前的indexa+1个元素和nums2索引为indexb和indexb之前的indexb+1个元素添加到数组C中,

更新want的值,计算want=(sumLen+1)/2-indexa-1-indexb-1。

记录上一次indexa和indexb的值为,indexa1=indexa,indexb1=indexb

更新indexa,indexb,indexa=indexa1+want/2,indexb=indexb+want/2

假设nums1[indexa]还是小于nums2[indexb],就对nums2再次进行二分找元素,直到nums1[indexa]>nums2[indexb],

假设indexb一次二分过后,nums1[indexa]>nums2[indexb],然后把nums1索引为indexa1之后和indexa之前的元素(左开右闭)和nums2索引为indexb1之后和indexb之前的元素(左开右闭)添加到数组C中,

重复做下去,直到indexa+1+indexb+1 = sumLen/2

  如果sumLen为奇数,说明nums[index+1]与nums2[indexb+1]两个元素较小的那个元素就是最终数组nums3的中位数,结束。

  如果sumLen为偶数,记录nums[indexa]与nums[indexb]中较大的值为c1,记录nums[indexa+1]与nums[indexb+1]中较小的值为c2,最终数组nums3的中位数为(c1+c2)/2

思路:
假设两个数组nums1与nums2都不为空(其中一个数组为空就比较简单)
第零步:计算两个数组的总长度sumLen=nums1.length+nums2.length
    int indexa=-1,indexb=-1;
    int indexa1=-1,,indexb1=-1;
    设nums1与nums2合并后得到的数组为nums3,nums3中位数之前的元素构成数组C,C最终的的长度为(sumLen+1)/2
    计算仍需向数组C添加元素的个数为want(最开始want=(sumLen+1)/2-indexa-1-indexb-1),
第一步:判断两个数组的中位数是否相等?
    相等,两个有序数组的中位数就是原来各自数组的中位数。
    不相等,进入第二步。
第二步:

    从nums1和nums2中各自取出indexa和indexb后面的want/2个元素进行比较(这儿需要判断indexa和indexb后面总数组元素长度和want/2的大小关系),再计算indexa或者indexb
    //更新indexa与indexb的值
    if(nums1.length-1<indexa+want/2){//eg: 0,9 1,7 2,3 3,2 4,4。length=5 want/2=5,indexa=-1,不满足,直接进入第三种情况
        indexb=indexb+want-(nums1.length-1-indexa);//当indexa=nums1.length-1;indexb=indexb+want;
        indexa=nums1.length-1;
    }else if( (indexb+want/2) > (nums2.length-1)){
        indexa=indexa+want-(nums2.length-1-indexb);
        indexb=nums2.length-1;
    }else{
        indexa=indexa+want/2; indexb=indexb+want/2;
    }
        


第三步:比较nums1[indexa]与nums2[indexb]的大小(谁大谁二分),
    ①如果,nums1[indexa]<nums2[indexb],就对nums2再次进行二分找元素(if indexb=indexb1+1,indexb=indexb1,else indexb=(indexb-indexb1+1)/2-1),直到nums1[indexa]>nums2[indexb],
        ①退出循环时,当indexb>=indexb1+1,证明能找到一个nums2[indexb],然后把nums1索引为indexa1+1到indexa的indexa+1个元素和nums2索引为indexb+1到indexb的indexb+1个元素添加到数组C中,
            计算want=(sumLen+1)/2-indexa-1-indexb-1。
            更新indexa1,indexb1;indexa1=indexa;indexb1=indexb;
        ②退出循环时,当indexb=indexb1,说明nums1[indexa]小于等于nums2还没有添加到C中的那部分元素的第一个元素,就把nums1数组的nums1[indexa1+1]到nums1[indexa]之前的元素添加到C中,
            计算want=(sumLen+1)/2-indexa-1-indexb-1.
            更新indexa1,indexb1;indexa1=indexa;indexb1=indexb;
    ②如果,nums2[indexb]<nums1[indexa],就对nums1再次进行二分查找元素,同理。
第四步:判断sumLen的奇偶性
    ①如果sumLen为奇数,判断indexa+1+indexb+1与(sumLen-1)/2大小,或者与sumLen/2的大小,因为奇数时,(sumLen-1)/2=sumLen/2
        ①indexa+1+indexb+1 = (sumLen-1)/2 ,说明nums[index+1]与nums2[indexb+1]两个元素较小的那个元素就是最终数组nums3的中位数,结束。
        ②indexa+1+indexb+1 < (sumLen-1)/2,
        
        indexa1=indexa;indexb1=indexb;//记录上次indexa、indexb的值
        回到第二步
        //更新indexa、indexb的值
            if( (indexa+want/2) > (nums1.length-1) ){
                indexb=indexb+want-(nums1.length-1-indexa);
                indexa=nums1.length-1;
            }else if( (indexb+want/2) > (nums2.length-1)){
                indexa=indexa+want-(nums2.length-1-indexb);
                indexb=nums2.length-1;
            }else{
                indexa=indexa+want/2; indexb=indexb+want/2;
            }
        比较nums1[indexa]与nums2[indexb]的大小(谁大谁二分),
    ②如果sumLen为偶数,判断indexa+1+indexb+1与sumLen/2大小
        ①indexa+1+indexb+1 = sumLen/2,记录nums[indexa]与nums[indexb]中较大的值为c1,记录nums[indexa+1]与nums[indexb+1]中较小的值为c2,最终数组nums3的中位数为(c1+c2)/2,结束。
        ②indexa+1+indexb+1 < sumLen/2,
            indexa1=indexa;indexb1=indexb;//记录上次indexa、indexb的值
            回到第二步

 时间复杂度好像不满足O(log(m+n)),不过这应该是一种可行的求解办法,有错误不足之处欢迎留言批评指正。

原文地址:https://www.cnblogs.com/sunupo/p/11239723.html