LeetCode 寻找两个有序数组的中位数(二分)

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。

请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。

示例 1:

nums1 = [1, 3]
nums2 = [2]

则中位数是 2.0
示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

则中位数是 (2 + 3)/2 = 2.5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解: 两个有序数组,建议在O(log(m + n))复杂度下计算,因此容易想到是二分了,但是又是两个数组的中位数,不能合并后再二分,只能充分利用两数组的有序信息来二分结果.

首先回忆一下中位数的意义,在有序数组中位置居中的那个数,目前有两个数组,我们定数组长度为len1和len2,合并后的总长度为len1+len2,其中中位数肯定存在于len1+len2的中间位置,也就是(len1+len2)/2 ,考虑到总数的奇偶关系,我们向上取整,即(len1+len2+1)/2.

接着,我们知道中位数的位置必定在(len1+len2+1)/2,但因为这是混合数组,我们无法确定这个数是A数组还是B数组.

但是我们知道,在这(len1+len2+1)/2个数字中,肯定存在一些A数组和B数组的值,至于是谁,我们用一下关系进行二分搜索.

在这(len1+len2+1)/2个数字中,我们定义A数组可能出现了前i个数,而B数组可能出现了j=(len1+len2+1)/2-i个数,这个很好理解,即A数组中的前i个数与B数组中的前j个数组成了合并后数组的前半部分.

为什么要说’前半部分’,而不说’一半’,因为有序的大小关系也是有意义的,可以知道,前半部分的最大值,一定小于或等于后半部分的最小值.

通过这个关系,我们首先二分尝试A数组中到底是前几个数存在于混合后的前半部分.比如我们尝试了A[i]这个数,并通过之前的关系得到了B数组中可能取到的数B[j],这个关系即,A数组取前i个数的情况下B数组取前(len1+len2+1)/2-i个数.

通过比较我们发现,当A[i] 取到的值 大于 B[j-1]个数 ,且 B[j] 取到的值 大于 A[i-1]个数时,此时前半部分的最大值不是A[i]就是B[j].

为什么呢?因为我们其实在这个过程中,是尽量搜索前半部分的最大值,但是我们这个最大值搜索是建立在两个数组的基础上的,那么最大值可能来自A数组也可能来自B数组,于是在符合两数组前i大和前j大,且i+j=(len1+len2+1)/2这个条件的情况下,我们取到了两数组可能出现的最大值位置,以至于再大就会找到后半部分的值了.

最后处理边界问题,这组数总数是奇数时,只需取一个值即可,那么这个值就是A[i-1]或B[j-1].取最大值返回

而当是偶数个时,取前半部分的最大值以及后半部分的最小值加和除二即中位数,那么只需要对A[i]和B[j]取最小值,然后加上上一步中的最大值结果除2即可

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        l1=len(nums1)
        l2=len(nums2)
        if l1>l2:
            l1,l2,nums1,nums2=l2,l1,nums2,nums1
        
        l=0
        r=l1
        half=(l1+l2+1)//2
        while l<=r:
            mid=(l+r)//2
            half_mid=half-mid
            if mid<l1 and nums1[mid]<nums2[half_mid-1]:
                l=mid+1
            elif mid>0 and nums1[mid-1]>nums2[half_mid]:
                r=mid-1
            else:
                if mid==0: ans= nums2[half_mid-1]
                elif half_mid==0:ans= nums1[mid-1]
                else:ans= max(nums1[mid-1],nums2[half_mid-1])
                if (l1+l2)%2==1:
                    return ans
                if mid==l1:res=nums2[half_mid]
                elif half_mid==l2:res=nums1[mid]
                else :res=min(nums2[half_mid],nums1[mid])
                return (ans+res)/2
posted @ 2019-06-28 17:35  KuroNekonano  阅读(366)  评论(0编辑  收藏  举报