寻找两个有序数组的中位数(C++)

先来了解一下割:

我们通过切一刀,能够把有序数组分成左右两个部分,切的那一刀就称为割(cut),割的左右会有两个元素,分别是左边最大值和右边最小值。

我们定义:LMax = Max(LeftPart), RMin = Min(RightPart)。

       割可以割在两个数中间,也可以割在一个数上,如果割在一个数上,那么这个数既属于 左 边,也属于右边。

奇数组:[2 , 3 , 5] 对应的中位数为 3 ,假定割( cut )在3上, 我们可以把 3 分为 2 个:[2  (3/3)  5],因此:LMax = 3 , RMin = 3

偶数组:[1 4 7 9] 对应的中位数为 (4 + 7) /2 = 5.5 ,假定割( cut )在4和7之间:[1  (4/7)  9],因此:LMax = 4 ,RMin = 7.

割和第k个元素:

一个数组

对于一个有序数组A,如果在k的位置割(cut)一下(不是割( cut )在两数中间),那么LMax = RMin = A[k].

两个数组:

也就是我们题目的状态,我们要求两个数合并成一个有序数组,第k位的元素

我们设:

Ci 为第 i 个数组的割。

LMaxi为第i个数组割后的左元素。

RMini为第i个数组割后的右元素。

首先,LMaxi <= RMini 这是肯定的。

其次,如果我们让LMax1 <= RMin2 ,LMax2 <= RMin1 呢,那么两个数组的左半边全小于右半边,如果左边的元素个数相加刚好等于k,那么第k个元素就是Max(LMax1, LMax2)。

那么如果 LMax1 > RMin2 , 说明数组1的左边元素太大,我们把C1减小, C2= k - C1也就相应增大;LMax2 > RMin1同理,把C2减小, C1 = K -C2 也就相应的增大。

假设 K = 3

 对于

        [2  3   5]

        [1  4  7  9]

设 C1 = 1 ,那么 C2 = k - C1 =2 ,即:

        [2  /  3   5]

        [1  4  / 7  9]

这时, LMax1 =2 ,RMin1 = 3 ,LMax2 = 4 ,RMin2 = 7,从而有LMax2 > RMin1 ,依据前面的推论,我们要将C1增大,所以我们让 C1 = 2 ,如下:

        [2  3 /   5]

        [1  /4  7  9]        

这时, LMax1 =3 ,RMin1 = 5 ,LMax2 = 1 ,RMin2 = 4,满足LMax1 < RMin2 ,LMax2 < RMin1 ,所以第3个元素为 Max(LMax1 , LMax2) = 3。

两个数组的最大问题是,他们合并后,m+n总数可能为奇,也可能为偶,所以我们得想办法让m+n总是为偶数。

通过虚拟加入 “#” , 我们让m转换成2m + 1 ,n转换成2n+1,两数之和就变成2m+2n+2,为偶数。要注意的是 ,我们这里是虚拟加,其实根本没有这一步,通过下面的转换,我们可以保证虚拟加后每个元素跟原来的元素一一对应:

        [#  2 # 3 #  5  #]

        [# 1 # 4 # 7 # 9 #]。

这样虚拟加之后,每个位置可以通过/2得到原来元素的位置。

而对于割( cut )而言,如果割在 “ #  ” 上等于割在 2 个元素之间,割在数字上等于把数字划到2个部分,总是有以下成立:

        LMaxi = (Ci - 1) / 2 位置上的元素

        RMini = Ci /2位置上的元素.

剩下的事情就好办了,把 2 个数组看做一个虚拟的数组A,A有2m+ 2n + 2个元素,割在m+n+1处,所以我们只需要找到m+n+1位和m+n+2位元素即可。

左边:A[m+n+1] = Max(LMax1 , LMax2)

右边:A[m+n+2] = Min(RMin1 , RMin2)

==> Mid  = (A[m+n+1]+A[m+n+2])/2

最快的割( cut )是二分法, 有两个数组,我们对那个做二分呢?根据之前的分析,我们知道了,只要C1或C2确定,另一个也就确定了。这里为了效率,我们肯定要选长度较小的进行二分,有二分递归公式:

        LMax1 >RMin2 , 把C1减小,C2增大.  ->C1向左二分。

        LMax2 >RMin1,  把C2减小,C1增大。->C1向右二分。

如果C1或C2到头了怎么办?我们假定 n < m,可能有4种情况:

        C1 = 0 ——  数组1整体都在右边了,所以都比中值大,中值在数组2中,简单的说就是数组1割后的左边是空了,我们可以假定LMax1 = INT_MIN

        C1 =2n——  数组1整体都在左边了,所以都比中值小,中值在数组2中,简单的说就是数组1割后的右边是空了,我们可以假定RMin1 = INT_MAX

        C2 = 0 ——  数组2整体都在右边了,所以都比中值大,中值在数组1中,简单的说就是数组1割后的左边是空了,我们可以假定LMax2 = INT_MIN

        C2 = 2m ——  数组1整体都在左边了,所以都比中值小,中值在数组1中,简单的说就是数组1割后的右边是空了,我们可以假定RMin2 = INT_MAX

你可能感兴趣的:(LeetCode刷题,算法)