LeetCode力扣_第四题_两正序数组组合的中位数
题目:给定两个大小分别为 m
和 n
的正序(从小到大)数组 nums1
和 nums2
。请你找出并返回这两个正序数组的 中位数 。
例子:nums1=[1,2],nums2=[3,4],那么中位数就是2.5。假如一个nums为空,那么中位数就是另外一数组的中位数。

答:首先最暴力、直接的解法就是合并数组,再排序求中位数。
这种解法在Python中实现比较简单,看下代码块:
利用数组的一些方法可以轻松完成算法实现。在力扣上的计算速度和内存占用都还行。但是在时间和空间复杂度上还是有待商榷的(ps:还未学习相关概念)。

接下来介绍在力扣官方解答中的解答:
一、二分查找法
首先要明白的就是上述的暴力解法是遍历了所有数字的。而二分查找法的优点就是去掉了一些数组片段,减少了多余的遍历工作。
一般来讲:对于两正序数组A、B分别为m、n项,其合并后的中位数是第(m+n)/2个【m+n为奇数】或第(m+n)/2个和第(m+n)/2+1个的平均值【m+n为偶数】,二分查找法的是令k=(m+n)/2或(m+n)/2+1,再在比较每个数组内的[k/2-1]项,这样就有最多2*(k/2-1)项的数比这两个数组中的[k/2-1]较小的项还小,下面就分情况来考虑:
当A[k/2-1]<B[k/2-1]时:那么可以的到A中的前[k/2-1]项数是一定在右边的,不可能是A+B中的中位数的,因此把A的前[k/2-1]项舍去。
当A[k/2-1]>B[k/2-1]时:同理舍去B的前[k/2-1]项。
当A[k/2-1]=B[k/2-1]时:这种情况其实舍去A、B中那个都无所谓,因为A、B中的前[k/2-1]项都是较小的,不可能是A+B的第k小的数。
那么这样就可以减少遍历片段以来节约时间,每次舍去一部分,舍去的那个数组的【0~k/2-1】项不在被遍历,因此遍历的数少了k/2个,那么k的值更新为k-k/2。那么下一步二分查找的时候就是更新后的k,比较新的A[k/2-1]和B[k/2-1]的大小,再舍去多余的片段。在这里因为去掉了k/2个,k的值逐渐减小,这样来二次划分会逐渐靠近中位数。即最开始的时候A+B的第k个。当k=1的时候,中位数也就是划分去掉后的两新数组的首项,比较其大小即最小的是第k小的数。
但是存在特殊情况,即A[k/2-1]和B[k/2-1]超界了,那么这个时候,就取对应的数组最后一个数,若是舍去的时候要舍去这个小数组,k值更新的时候去掉小数组的个数,而不是取掉k/2;A/B若有一个是空的,那么只需要考虑另外一个数组的第k个就行,那即A+B中第k小的数。
python代码如下:
看到官方的这个解答,佩服把算法代码化的实力,自己还需要多努力!!!这里就不画流程图了,主要解释下代码实现算法的思路:
这里是创建了一个函数获取的第k个数,函数的参数是由两数组的程度决定的,可以看到这里判别了数组的长度是奇数还是偶数,是奇数就是第k个数就是中位数,偶数是取中间两数的平均值。故会有上述代码的主函数段。k的值确定后,看getKelement(k)是怎么操作的?首先是创建了两索引index,再判断特殊情况,首先是两者空数组的情况,直接返回另外数组的第k个数;然后判断k是否更新到1了,是的话返回首项最小值。重点是正常的情况,每个数组创建一个新的索引,新的索引是之前的索引+k//2-1和数组右边界的最小值(出界的情况考虑进去了),第一步是可以理解的,就是第[k//2-1]项,然后比较大小,再根据情况更新k的值,就是k-k//2,之所以后面加1是数组索引是从0开始的。后面的index赋值也是同样的道理,因为从0~k//2-1都舍去了,就从k//2开始了。然后就继续二分了,这里我开始以为会重新创建数组,后来发现是我菜了,只是指针的范围往前走了就行。newindex后面的赋值因为从index开始取值了,故需要加上index。
二、划分数组
这里是最np的算法了,首先咱要理解中位数的定义了。
中位数是将一个集合划分为两个长度相等的子集,其中一个子集中的元素总是大于另一个子集中的元素。
在这里我们要注意关键词 长度相等,一个子集的元素总是大于或等于另外一个子集的元素;
这是这个算法的主要逻辑,也就是把A+B划分为两个子集,其中一个子集的最大值总是小于另外一个子集的最小值。且两子集的数字个数相同或 数值小的子集多一个数。

上图是算法的示意图,A/B在i/j位置分割,使得左边的元素个数等于右边的元素个数。且满足下面公式:
1式中的主要目的是判别左边的最大值是否小于或等于右边的最小值。2式的主要目的是使得左右两边的元素个数相同。当不满足的时候,需要调整i的值,从而j的值也会改变,那么A/B两数组进行左右移动,一直保持着2式的关系,即虚线两侧的元素个数相同。其中1式式可以等价于存在最大的i值,使得:
因此遍历A数组寻找满足上述条件的最大i值,因此一般使元素数目较小的数组作为A,这样求解的时候较快。
但是存在情况就是,A数组的元素过少,以致i==0,或者i==m了,这个时候就是出界了。处理的方法就是当i==0的时候,[i-1]项为-∞。i==m时,[i]为+∞。这个处理并不影响上述的逻辑。当A数组为空的时候,1式条件是永远满足的,就是使得2式条件满足即可,也就是查找一个正序数组的中位数。
下面是我膜拜的代码:
膜拜的主要点是
i的值是用二分查找,分别调整left和right的值
始终贯彻着中位数的概念
把特殊情况也得包括进去了

记录学习,生生不息~,