zoukankan      html  css  js  c++  java
  • 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
    
  • 相关阅读:
    Educational Codeforces Round 83 --- F. AND Segments
    Educational Codeforces Round 83 --- G. Autocompletion
    SEERC 2019 A.Max or Min
    2019-2020 ICPC Southwestern European Regional Programming Contest(Gym 102501)
    Educational Codeforces Round 78 --- F. Cards
    今天我学习了一门全新的语言
    codeforces 1323D 题解(数学)
    Educational Codeforces Round 80 (Div. 2) 题解 1288A 1288B 1288C 1288D 1288E
    Educational Codeforces Round 81 (Div. 2) 题解 1295A 1295B 1295C 1295D 1295E 1295F
    Codeforces Round #617 (Div. 3) 题解 1296C 1296D 1296E 1296F
  • 原文地址:https://www.cnblogs.com/kuronekonano/p/11135643.html
Copyright © 2011-2022 走看看