算法系列一:寻找两个有序数组的中位数

题目

两个正序数组s1和s2,分别有m和n个元素,现求这m+n个元素的中位数
注:m和n不同时为0

思路

寻找到目标元素

首先要明确目标,我们已知数组是正序的,所以只需要找到总共第(m+n)/2个元素(可能还有第(m+n)/2+1个)。明确目标之后,就是具体的寻找。
我们首先确定一个割(cut)的概念,cut在两个数字之间代表将数组分为左右两个部分,这样就可以将问题变化为求两个分割使得两个数组被分为4个部分,并且左边部分元素个数和右边部分元素个数尽可能相等。

取自leetcode上一位大佬的图片

由上图我们接着分析,假定我们需要求第k和k+1大的元素,则令num(LeftPart)=k,有我们求max(l1max,l2max)和min(r1min,r2min)。
接着分析,由于数组是正序的,l1max<r1min,l2max<r2min。所以只需要分析l1max和r2min,l2max和r2min之间的关系。
一、l1max<r2min,l2max<r1min。此时有左边全部小于右边,可以直接获取第k大和k+1大的元素。
二、l1max>r2min,l2max<r1min。此时有数组一的左边部分的数据过大,数组一的分割需要向左移动,为了保证两个数组左边部分元素个数固定,数组二的分割需要向右移动。
三、l1max<r2min,l2max>r1min。此时有数组二的左边部分的数据过大,数组二的分割需要向左移动,为了保证两个数组左边部分元素个数固定,数组一的分割需要向右移动
四、l1max>r2min,l2max>r1min。出现矛盾,不存在该情况。

分割的方式

在上述过程中,我们已经明确了如何获取所需要的元素,接下来思考如何分割,一个很显然的问题在于数组元素个数有奇偶之分,这不利于接下来的思考,所以我们需要对数组进行逻辑上的插入。

原来的数组s新的数组
1,2,3#,1,#,2,#,3,#
1,2,3,4#,1,#,2,#,3,#,4,#

为了与代码保持一致,我们从0开始计数,可以验证,当我们以第ci个元素作为分界线,无论ci对应的是数字还是#,都有s[(ci-1)/2]和s[(ci)/2]均为数字(这两个下标均向下取整,这两个可以相等,此时lmax==rmin),于是我们就可以定义下列式子

lmaxs[(ci-1)/2]
rmins[(ci)/2]
分割的数组长度为0

在分割过程中,分割出来的数组长度可能变为0,此时就需要我们进行处理,如果是左边长度为0,则可以将数据的左边部分lmax设置为INT_MIN
右边则设置为INT_MAX,这样就可以保证不会影响数组的最终结果
下面为代码

下面展示一些 内联代码片

int findMax(int a,int b)
{
    return a>b?a:b;
}

int findMin(int a,int b)
{
    return a>b?b:a;
}

double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size){
int max=nums1Size*2,min=0;//通过插入#实现将m和n都化为偶数数组,共计2*(m+n+1)
int l1max,l2max,r1min,r2min,c1,c2;//这里c表示切割第几个,其余的表示用来比较的
if(nums1Size>nums2Size)
    return findMedianSortedArrays( nums2,  nums2Size, nums1, nums1Size);
while(min<=max)
{
    c1=(max+min)/2;//通过插入nums1Size+1个#可以方便计算
    c2=nums1Size+nums2Size-c1;
    l1max=(c1==0)?INT_MIN:nums1[(c1-1)/2];
    l2max=(c2==0)?INT_MIN:nums2[(c2-1)/2];
    r1min=(c1==2*nums1Size)?INT_MAX:nums1[c1/2];
    r2min=(c2==2*nums2Size)?INT_MAX:nums2[c2/2];//通过计算得到当前需要比较的四个元素的值,方便接下来的判断
    if(l1max<=r2min&&l2max<=r1min)
        return ((double)(findMax(l1max,l2max)+findMin(r1min,r2min)))/2.0;
    else if(l1max<r2min&&l2max>r1min)//此时数组1左边过小,需要向右移动,向右二分,则将min向右边移动就行
        min=c1+1;
    else max=c1-1;//最后一种情况下将会把max向左移动以使得c1向左移动
}
return ((double)(findMax(l1max,l2max)+findMin(r1min,r2min)))/2.0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值